天天看點

java一些常用并發工具示例

最近把《java并發程式設計實戰》-Java Consurrency in Practice 重溫了一遍,把書中提到的一些常用工具記錄于此:

一、閉鎖(門栓)- CountDownLatch

适用場景:多線程測試時,通常為了精确計時,要求所有線程都ready後,才開始執行,防止有線程先起跑,造成不公平,類似的,所有線程執行完,整個程式才算運作完成。

執行結果:

線程-1 is running...

線程-5 is running...

線程-8 is running...

線程-4 is running...

線程-3 is running...

線程-0 is running...

線程-2 is running...

線程-9 is running...

線程-7 is running...

線程-6 is running...

done! exec time => 13 ms

注:大家可以把第14行注釋掉,再看看運作結果有什麼不同。

二、信号量(Semaphore)

适用場景:用于資源數有限制的并發通路場景。

上面的示例将一個普通的Set變成了有界容器。執行結果如下:

0 added !

1 added !

2 added !

3 added !

4 added !

5 not add to Set!

三、栅欄CyclicBarrier 

這個跟閉鎖類似,可以通過代碼設定一個『屏障』點,其它線程到達該點後才能繼續,常用于限制其它線程都到達某一狀态後,才允許做後面的事情。

這裡我們假設有一個worder線程,裡面有2步操作,要求所有線程完成step1後,才能繼續step2. 執行結果如下:

Thread-0 step 1 ...

Thread-1 step 1 ...

Thread-2 step 1 ...

Thread-3 step 1 ...

Thread-4 step 1 ...

Thread-5 step 1 ...

Thread-6 step 1 ...

Thread-7 step 1 ...

Thread-8 step 1 ...

Thread-9 step 1 ...

Thread-9 step 2 ...

Thread-0 step 2 ...

Thread-3 step 2 ...

Thread-4 step 2 ...

Thread-6 step 2 ...

Thread-2 step 2 ...

Thread-1 step 2 ...

Thread-8 step 2 ...

Thread-7 step 2 ...

Thread-5 step 2 ...

四、Exchanger

如果2個線程需要交換資料,Exchanger就能派上用場了,見下面的示例:

 執行結果:

thread 1 交換前:AAAAAA

thread 2 交換前:BBBBBB

thread 2 交換後:AAAAAA

thread 1 交換後:BBBBBB

五、FutureTask/Future

一些很耗時的操作,可以用Future轉化成異步,不阻塞後續的處理,直到真正需要傳回結果時調用get拿到結果

就緒。。。

主線程其它處理。。。

很耗時的操作進行中。。。

done

處理完成!

-----------------

executor 就緒。。。

六、阻塞隊列BlockingQueue

阻塞隊列可以線上程間實作生産者-消費者模式。比如下面的示例:線程producer模拟快速生産資料,而線程consumer模拟慢速消費資料,當達到隊列的上限時(即:生産者産生的資料,已經放不下了),隊列就堵塞住了。

producer 1 産生了一個數字:6773

consumer 1 消費了一個數字:6773

producer 1 産生了一個數字:4456

producer 1 産生了一個數字:8572

producer 1 産生了一個數字:5764

producer 1 産生了一個數字:2874

producer 1 産生了一個數字:780 # 注意這裡就已經堵住了,直到有消費者消費一條資料,才能繼續生産

consumer 1 消費了一個數字:4456

producer 1 産生了一個數字:4193