激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

香港云服务器
服務器之家 - 編程語言 - JAVA教程 - Java并發之條件阻塞Condition的應用代碼示例

Java并發之條件阻塞Condition的應用代碼示例

2021-04-01 12:27eson_15 JAVA教程

這篇文章主要介紹了Java并發之條件阻塞Condition的應用代碼示例,分享了相關代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下

本文研究的主要是Java并發之條件阻塞Condition的應用示例代碼,具體如下。

Condition將Object監視器方法(wait、notify 和 notifyAll)分解成截然不同的對象,以便通過將這些對象與任意Lock實現組合使用,為每個對象提供多個等待 set(wait-set)。其中,Lock 替代了synchronized方法和語句的使用,Condition替代了Object監視器方法的使用。

1. Condition的基本使用

 

  由于Condition可以用來替代wait、notify等方法,所以可以對比著之前寫過的線程間通信的代碼來看,再來看一下原來那個問題:

有兩個線程,子線程先執行10次,然后主線程執行5次,然后再切換到子線程執行10,再主線程執行5次……如此往返執行50次。

  之前用wait和notify來實現的,現在用Condition來改寫一下,代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public class ConditionCommunication {
    public static void main(String[] args) {
        Business bussiness = new Business();
        new Thread(new Runnable() {
            // 開啟一個子線程
            @Override
                      public void run() {
                for (int i = 1; i <= 50; i++) {
                    bussiness.sub(i);
                }
            }
        }
        ).start();
        // main方法主線程
        for (int i = 1; i <= 50; i++) {
            bussiness.main(i);
        }
    }
}
class Business {
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    //Condition是在具體的lock之上的
    private Boolean bShouldSub = true;
    public void sub(int i) {
        lock.lock();
        try {
            while (!bShouldSub) {
                try {
                    condition.await();
                    //用condition來調用await方法
                }
                catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            for (int j = 1; j <= 10; j++) {
                System.out.println("sub thread sequence of " + j
                            + ", loop of " + i);
            }
            bShouldSub = false;
            condition.signal();
            //用condition來發出喚醒信號,喚醒某一個
        }
        finally {
            lock.unlock();
        }
    }
    public void main(int i) {
        lock.lock();
        try {
            while (bShouldSub) {
                try {
                    condition.await();
                    //用condition來調用await方法
                }
                catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            for (int j = 1; j <= 10; j++) {
                System.out.println("main thread sequence of " + j
                            + ", loop of " + i);
            }
            bShouldSub = true;
            condition.signal();
            //用condition來發出喚醒信號么,喚醒某一個
        }
        finally {
            lock.unlock();
        }
    }
}

從代碼來看,Condition的使用時和Lock一起的,沒有Lock就沒法使用Condition,因為Condition是通過Lock來new出來的,這種用法很簡單,只要掌握了synchronized和wait、notify的使用,完全可以掌握Lock和Condition的使用。

2. Condition的拔高

 

2.1 緩沖區的阻塞隊列

  上面使用Lock和Condition來代替synchronized和Object監視器方法實現了兩個線程之間的通信,現在再來寫個稍微高級點應用:模擬緩沖區的阻塞隊列。
什么叫緩沖區呢?舉個例子,現在有很多人要發消息,我是中轉站,我要幫別人把消息發出去,那么現在我  就需要做兩件事,一件事是接收用戶發過來的消息,并按順序放到緩沖區,另一件事是從緩沖區中按順序取出用戶發過來的消息,并發送出去。

  現在把這個實際的問題抽象一下:緩沖區即一個數組,我們可以向數組中寫入數據,也可以從數組中把數據取走,我要做的兩件事就是開啟兩個線程,一個存數據,一個取數據。但是問題來了,如果緩沖區滿了,說明接收的消息太多了,即發送過來的消息太快了,我另一個線程還來不及發完,導致現在緩沖區沒地方放了,那么此時就得阻塞存數據這個線程,讓其等待;相反,如果我轉發的太快,現在緩沖區所有內容都被我發完了,還沒有用戶發新的消息來,那么此時就得阻塞取數據這個線程。

  好了,分析完了這個緩沖區的阻塞隊列,下面就用Condition技術來實現一下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class Buffer {
    final Lock lock = new ReentrantLock();
    //定義一個鎖
    final Condition notFull = lock.newCondition();
    //定義阻塞隊列滿了的Condition
    final Condition notEmpty = lock.newCondition();
    //定義阻塞隊列空了的Condition
    final Object[] items = new Object[10];
    //為了下面模擬,設置阻塞隊列的大小為10,不要設太大
    int putptr, takeptr, count;
    //數組下標,用來標定位置的
    //往隊列中存數據
    public void put(Object x) throws InterruptedException {
        lock.lock();
        //上鎖
        try {
            while (count == items.length) {
                System.out.println(Thread.currentThread().getName() + " 被阻塞了,暫時無法存數據!");
                notFull.await();
                //如果隊列滿了,那么阻塞存數據這個線程,等待被喚醒
            }
            //如果沒滿,按順序往數組中存
            items[putptr] = x;
            if (++putptr == items.length) //這是到達數組末端的判斷,如果到了,再回到始端
            putptr = 0;
            ++count;
            //消息數量
            System.out.println(Thread.currentThread().getName() + " 存好了值: " + x);
            notEmpty.signal();
            //好了,現在隊列中有數據了,喚醒隊列空的那個線程,可以取數據啦
        }
        finally {
            lock.unlock();
            //放鎖
        }
    }
    //從隊列中取數據
    public Object take() throws InterruptedException {
        lock.lock();
        //上鎖
        try {
            while (count == 0) {
                System.out.println(Thread.currentThread().getName() + " 被阻塞了,暫時無法取數據!");
                notEmpty.await();
                //如果隊列是空,那么阻塞取數據這個線程,等待被喚醒
            }
            //如果沒空,按順序從數組中取
            Object x = items[takeptr];
            if (++takeptr == items.length) //判斷是否到達末端,如果到了,再回到始端
            takeptr = 0;
            --count;
            //消息數量
            System.out.println(Thread.currentThread().getName() + " 取出了值: " + x);
            notFull.signal();
            //好了,現在隊列中有位置了,喚醒隊列滿的那個線程,可以存數據啦
            return x;
        }
        finally {
            lock.unlock();
            //放鎖
        }
    }
}

這個程序很經典,我從官方JDK文檔中拿出來的,然后加了注釋。程序中定義了兩個Condition,分別針對兩個線程,等待和喚醒分別用不同的Condition來執行,思路很清晰,程序也很健壯。可以考慮一個問題,為啥要用兩個Codition呢?之所以這么設計肯定是有原因的,如果用一個Condition,現在假設隊列滿了,但是有2個線程A和B同時存數據,那么都進入了睡眠,好,現在另一個線程取走一個了,然后喚醒了其中一個線程A,那么A可以存了,存完后,A又喚醒一個線程,如果B被喚醒了,那就出問題了,因為此時隊列是滿的,B不能存的,B存的話就會覆蓋原來還沒被取走的值,就因為使用了一個Condition,存和取都用這個Condition來睡眠和喚醒,就亂了套。到這里,就能體會到這個Condition的用武之地了,現在來測試一下上面的阻塞隊列的效果:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class BoundedBuffer {
    public static void main(String[] args) {
        Buffer buffer = new Buffer();
        for (int i = 0; i < 5; i ++) {
            //開啟5個線程往緩沖區存數據
            new Thread(new Runnable() {
                @Override
                        public void run() {
                    try {
                        buffer.put(new Random().nextint(1000));
                        //隨機存數據
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            ).start();
        }
        for (int i = 0; i < 10; i ++) {
            //開啟10個線程從緩沖區中取數據
            new Thread(new Runnable() {
                @Override
                        public void run() {
                    try {
                        buffer.take();
                        //從緩沖區取數據
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            ).start();
        }
    }
}

我故意只開啟5個線程存數據,10個線程取數據,就是想讓它出現取數據被阻塞的情況發生,看運行的結果:

Thread-5 被阻塞了,暫時無法取數據!
Thread-10 被阻塞了,暫時無法取數據!
Thread-1 存好了值: 755
Thread-0 存好了值: 206
Thread-2 存好了值: 741
Thread-3 存好了值: 381
Thread-14 取出了值: 755
Thread-4 存好了值: 783
Thread-6 取出了值: 206
Thread-7 取出了值: 741
Thread-8 取出了值: 381
Thread-9 取出了值: 783
Thread-5 被阻塞了,暫時無法取數據!
Thread-11 被阻塞了,暫時無法取數據!
Thread-12 被阻塞了,暫時無法取數據!
Thread-10 被阻塞了,暫時無法取數據!
Thread-13 被阻塞了,暫時無法取數據!

  從結果中可以看出,線程5和10搶先執行,發現隊列中沒有,于是就被阻塞了,睡在那了,直到隊列中有新的值存入才可以取,但是它們兩運氣不好,存的數據又被其他線程給搶先取走了,哈哈……可以多運行幾次。如果想要看到存數據被阻塞,可以將取數據的線程設置少一點,這里我就不設了。

2.2 兩個以上線程之間的喚醒

  還是原來那個題目,現在讓三個線程來執行,看一下題目:

有三個線程,子線程1先執行10次,然后子線程2執行10次,然后主線程執行5次,然后再切換到子線程1執行10次,子線程2執行10次,主線程執行5次……如此往返執行50次。

  如過不用Condition,還真不好弄,但是用Condition來做的話,就非常方便了,原理很簡單,定義三個Condition,子線程1執行完喚醒子線程2,子線程2執行完喚醒主線程,主線程執行完喚醒子線程1。喚醒機制和上面那個緩沖區道理差不多,下面看看代碼吧,很容易理解。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
public class ThreeConditionCommunication {
    public static void main(String[] args) {
        Business bussiness = new Business();
        new Thread(new Runnable() {
            // 開啟一個子線程
            @Override
                      public void run() {
                for (int i = 1; i <= 50; i++) {
                    bussiness.sub1(i);
                }
            }
        }
        ).start();
        new Thread(new Runnable() {
            // 開啟另一個子線程
            @Override
                  public void run() {
                for (int i = 1; i <= 50; i++) {
                    bussiness.sub2(i);
                }
            }
        }
        ).start();
        // main方法主線程
        for (int i = 1; i <= 50; i++) {
            bussiness.main(i);
        }
    }
    static class Business {
        Lock lock = new ReentrantLock();
        Condition condition1 = lock.newCondition();
        //Condition是在具體的lock之上的
        Condition condition2 = lock.newCondition();
        Condition conditionMain = lock.newCondition();
        private int bShouldSub = 0;
        public void sub1(int i) {
            lock.lock();
            try {
                while (bShouldSub != 0) {
                    try {
                        condition1.await();
                        //用condition來調用await方法
                    }
                    catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                for (int j = 1; j <= 10; j++) {
                    System.out.println("sub1 thread sequence of " + j
                                  + ", loop of " + i);
                }
                bShouldSub = 1;
                condition2.signal();
                //讓線程2執行
            }
            finally {
                lock.unlock();
            }
        }
        public void sub2(int i) {
            lock.lock();
            try {
                while (bShouldSub != 1) {
                    try {
                        condition2.await();
                        //用condition來調用await方法
                    }
                    catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                for (int j = 1; j <= 10; j++) {
                    System.out.println("sub2 thread sequence of " + j
                                  + ", loop of " + i);
                }
                bShouldSub = 2;
                conditionMain.signal();
                //讓主線程執行
            }
            finally {
                lock.unlock();
            }
        }
        public void main(int i) {
            lock.lock();
            try {
                while (bShouldSub != 2) {
                    try {
                        conditionMain.await();
                        //用condition來調用await方法
                    }
                    catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                for (int j = 1; j <= 5; j++) {
                    System.out.println("main thread sequence of " + j
                                  + ", loop of " + i);
                }
                bShouldSub = 0;
                condition1.signal();
                //讓線程1執行
            }
            finally {
                lock.unlock();
            }
        }
    }
}

代碼看似有點長,但是是假象,邏輯非常簡單。關于線程中的Condition技術就總結這么多吧。

總結

 

以上就是本文關于Java并發之條件阻塞Condition的應用代碼示例的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站其他相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!

原文鏈接:http://blog.csdn.net/eson_15/article/details/51559860

延伸 · 閱讀

精彩推薦
994
主站蜘蛛池模板: 国产精品爆操 | 亚洲欧美日韩综合一区 | 天天操很很操 | 欧美日本一 | 羞羞视频免费网站 | 91精品福利视频 | 久久青草影院 | 亚洲电影在线观看高清免费 | 美女黄页网站免费进入 | 国产剧情在线观看一区二区 | 西川av在线一区二区三区 | 精品国产91一区二区三区 | 久久免费视频一区 | chinese hd xxxx tube| 国产理论视频在线观看 | 91精品国产综合久久久动漫日韩 | 久久草在线视频免费 | 国产午夜免费不卡精品理论片 | 91美女视频在线观看 | 中文在线观看www | 一级毛片真人免费播放视频 | 奇米影视奇米色777欧美 | 精国产品一区二区三区 | 国产福利不卡一区二区三区 | 久久国产精品成人免费网站 | 久久久精品视频国产 | 欧美一级理论 | 久久精品视频69 | 日韩欧美高清片 | 欧美成人性生活 | 精品国产一区二区三区天美传媒 | 国产伦久视频免费观看视频 | 久久成人午夜视频 | 国产精品视频免费网站 | 曰韩毛片 | 爽爽淫人网 | 国产精品久久久久久久久久iiiii | 一级毛片特黄 | 天海翼无删减av三级在线观看 | 日韩激情一区二区三区 | 男女无套免费视频 |