多執行緒與併發----CycliBarrier、CountDownLatch 和 Exchanger同步
一、CycliBarrier
表示大家彼此等待,大家集合號後才開始出發,分散活動後又在指定地點集合碰面,這就好比整個公司的人員利用週末時間集體郊遊一樣,先各自從家出發到公司集合後,在他同時出發到公園遊玩,在指定地點集合後再同時就餐。
功能:
一個同步輔助類,它允許一組執行緒互相等待,直到到達某個公共屏障點 (common barrier point)。在涉及一組固定大小的執行緒的程式中,這些執行緒必須不時地互相等待,此時 CyclicBarrier 很有用。因為該 barrier 在釋放等待執行緒後可以重用,所以稱它為迴圈 的 barrier。
CyclicBarrier 支援一個可選的 Runnable 命令,在一組執行緒中的最後一個執行緒到達之後(但在釋放所有執行緒之前),該命令只在每個屏障點執行一次。若在繼續所有參與執行緒之前更新共享狀態,此屏障操作 很有用。
構造方法摘要
CyclicBarrier(int parties) 建立一個新的 CyclicBarrier,它將在給定數量的參與者(執行緒)處於等待狀態時啟動,但它不會在啟動 barrier 時執行預定義的操作。
CyclicBarrier(int parties, Runnable barrierAction) 建立一個新的 CyclicBarrier,它將在給定數量的參與者(執行緒)處於等待狀態時啟動,並在啟動 barrier 時執行給定的屏障操作,該操作由最後一個進入 barrier 的執行緒執行。
方法摘要
int
int
await(long timeout, TimeUnit unit) 在所有參與者都已經在此屏障上呼叫 await 方法之前將一直等待,或者超出了指定的等待時間。
int
getNumberWaiting() 返回當前在屏障處等待的參與者數目。
int
boolean
isBroken() 查詢此屏障是否處於損壞狀態。
void
reset() 將屏障重置為其初始狀態。
示例程式碼:
import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CylicBarrierTest { public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); final CyclicBarrier cb = new CyclicBarrier(3); //約定3個人 for (int i=0; i<3; i++)//產生3個人 { //每個人的任務 Runnable runnable = new Runnable() { public void run() { try { //開始出發到目的地 Thread.sleep((long)Math.random()*10000); System.out.println("執行緒 "+Thread.currentThread().getName()+ " 即將到達集合地點1,當前已有 "+(cb.getNumberWaiting()+1)+ " 個到達,"+(cb.getNumberWaiting()==2?" 都到齊了,繼續走啊 ":" 正在等候")); cb.await();//到了其他人沒來就等人到齊了再繼續進行 Thread.sleep((long)Math.random()*10000); System.out.println("執行緒 "+Thread.currentThread().getName()+ " 即將到達集合地點2,當前已有 "+(cb.getNumberWaiting()+1)+ " 個到達,"+(cb.getNumberWaiting()==2?" 都到齊了,繼續走啊 ":" 正在等候 ")); cb.await();//到了其他人沒來就等人到齊了再繼續進行 Thread.sleep((long)Math.random()*10000); System.out.println("執行緒 "+Thread.currentThread().getName()+ " 即將到達集合地點3,當前已有 "+(cb.getNumberWaiting()+1)+ " 個到達,"+(cb.getNumberWaiting()==2?" 都到齊了,繼續走啊 ":" 正在等候")); //cb.await(); } catch (Exception e) { e.printStackTrace(); } } }; service.execute(runnable); } //service.shutdown(); } }
執行結果為:
執行緒 pool-1-thread-1 即將到達集合地點1,當前已有 1 個到達, 正在等候
執行緒 pool-1-thread-2 即將到達集合地點1,當前已有 2 個到達, 正在等候
執行緒 pool-1-thread-3 即將到達集合地點1,當前已有 3 個到達, 都到齊了,繼續走啊
執行緒 pool-1-thread-3 即將到達集合地點2,當前已有 1 個到達, 正在等候
執行緒 pool-1-thread-1 即將到達集合地點2,當前已有 2 個到達, 正在等候
執行緒 pool-1-thread-2 即將到達集合地點2,當前已有 3 個到達, 都到齊了,繼續走啊
二、CountDownLatch
1、功能:
好像倒數計時計數器,呼叫CountDownLatch物件的countDown方法就將計數器減 1,當到達 0 時,所有等待著就開始執行。
2、原理
java.util.concurrent.CountDownLatch
一個同步輔助類,在完成一組正在其他執行緒中執行的操作之前,它允許一個或多個執行緒一直等待。 用給定的計數 初始化 CountDownLatch。由於呼叫了 countDown() 方法,所以在當前計數到達零之前,await 方法會一直受阻塞。之後,會釋放所有等待的執行緒,await 的所有後續呼叫都將立即返回。這種現象只出現一次——計數無法被重置。如果需要重置計數,請考慮使用 CyclicBarrier。
CountDownLatch 是一個通用同步工具,它有很多用途。將計數 1 初始化的 CountDownLatch 用作一個簡單的開/關鎖存器,或入口:在通過呼叫 countDown() 的執行緒開啟入口前,所有呼叫 await 的執行緒都一直在入口處等待。用 N 初始化的 CountDownLatch 可以使一個執行緒在 N 個執行緒完成某項操作之前一直等待,或者使其在某項操作完成 N 次之前一直等待。
CountDownLatch 的一個有用特性是,它不要求呼叫 countDown 方法的執行緒等到計數到達零時才繼續,而在所有執行緒都能通過之前,它只是阻止任何執行緒繼續通過一個 await。
構造方法摘要
CountDownLatch(int count) 構造一個用給定計數初始化的 CountDownLatch。
方法摘要
void
boolean
await(long timeout, TimeUnit unit) 使當前執行緒在鎖存器倒計數至零之前一直等待,除非執行緒被中斷或超出了指定的等待時間。
void
countDown() 遞減鎖存器的計數,如果計數到達零,則釋放所有等待的執行緒。
long
getCount() 返回當前計數。
toString() 返回標識此鎖存器及其狀態的字串。
示例程式碼:多個運動員等待裁判命令: 裁判等所有運動員到齊後釋出結果
import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CountdownLatchTest { public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); //裁判釋出命令的計數器,計數器為0,運動員就跑 final CountDownLatch cdOrder = new CountDownLatch(1); //運動員跑到終點的計數器,為0裁判宣佈結果 final CountDownLatch cdAnswer = new CountDownLatch(3); //產生3個運動員 for (int i=0; i<3; i++) { //運動員的任務 Runnable runnable = new Runnable(){ public void run() { try { System.out.println("執行緒"+Thread.currentThread().getName()+"正準備接受命令"); //等待發布命令 cdOrder.await(); //計數器為0繼續向下執行 System.out.println("執行緒"+Thread.currentThread().getName()+"已接受命令"); Thread.sleep((long)(Math.random()*10000));//開始跑步 System.out.println("執行緒"+Thread.currentThread().getName()+"回應命令處理結果"); cdAnswer.countDown();//跑到終點了,計數器減1 } catch (Exception e) { e.printStackTrace(); } } }; service.execute(runnable);//運動員開始任務 } try { Thread.sleep((long)(Math.random()*10000));//開始跑步 System.out.println("執行緒"+Thread.currentThread().getName()+"即將釋出命令"); cdOrder.countDown();//跑到終點了,計數器減1 System.out.println("執行緒"+Thread.currentThread().getName()+"已傳送命令,正在等待結果"); cdAnswer.await(); System.out.println("執行緒"+Thread.currentThread().getName()+"已收到所有響應結果"); } catch (Exception e) { e.printStackTrace(); } service.shutdown(); } }
執行結果為:
執行緒pool-1-thread-2正準備接受命令
執行緒pool-1-thread-3正準備接受命令
執行緒pool-1-thread-1正準備接受命令
執行緒main即將釋出命令
執行緒main已傳送命令,正在等待結果
執行緒pool-1-thread-1已接受命令
執行緒pool-1-thread-2已接受命令
執行緒pool-1-thread-3已接受命令
執行緒pool-1-thread-3回應命令處理結果
執行緒pool-1-thread-1回應命令處理結果
執行緒pool-1-thread-2回應命令處理結果
執行緒main已收到所有響應結果
三、Exchanger
1、功能
用於實現兩個人之間的資料交換,每個人在完成一定的事務後想與對方交換資料,第一個先拿出資料的人會一直等待第二個人,直到第二個人拿著資料到來時,才能彼此交換資料。
2、原理
java.util.concurrent.Exchanger<V> V - 可以交換的物件型別
可以在對中對元素進行配對和交換的執行緒的同步點。每個執行緒將條目上的某個方法呈現給 exchange 方法,與夥伴執行緒進行匹配,並且在返回時接收其夥伴的物件。Exchanger 可能被視為 SynchronousQueue 的雙向形式。Exchanger 可能在應用程式(比如遺傳演算法和管道設計)中很有用。
構造方法摘要
Exchanger() 建立一個新的 Exchanger。
方法摘要
exchange(V x) 等待另一個執行緒到達此交換點(除非當前執行緒被中斷),然後將給定的物件傳送給該執行緒,並接收該執行緒的物件。
exchange(V x, long timeout, TimeUnit unit) 等待另一個執行緒到達此交換點(除非當前執行緒被中斷,或者超出了指定的等待時間),然後將給定的物件傳送給該執行緒,同時接收該執行緒的物件。
3、舉例
毒品交易 雙方並不是同時到達,有先有後,只有都到達了,瞬間交換資料,各自飛
程式碼演示:
import java.util.concurrent.Exchanger; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExchangerTest { public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); final Exchanger exchanger = new Exchanger(); //毒販: service.execute(new Runnable() { //毒販做的事 public void run() { try { String data1 ="abc"; System.out.println("執行緒 "+Thread.currentThread().getName()+ " 正在把資料 "+data1+" 換出去"); Thread.sleep((long)(Math.random()*10000)); //換的過程 //毒販到位了,拿著毒品等待毒人接頭,接頭後就能換到錢了 String data2 = (String)exchanger.exchange(data1); System.out.println("執行緒 "+Thread.currentThread().getName()+"換回的資料為 "+data2); } catch (Exception e) { e.printStackTrace(); } } }); //毒人: service.execute(new Runnable() { //吸毒人做的事 public void run() { try { String data1 ="123"; System.out.println("執行緒 "+Thread.currentThread().getName()+ " 正在把資料 "+data1+" 換出去"); Thread.sleep((long)(Math.random()*10000)); //換的過程 //吸毒人到位了,拿著錢等待毒販接頭,接頭後就能換到毒品了 String data2 = (String)exchanger.exchange(data1); System.out.println("執行緒 "+Thread.currentThread().getName()+"換回的資料為 "+data2); } catch (Exception e) { e.printStackTrace(); } } }); } }
執行結果為:
執行緒 pool-1-thread-1 正在把資料 abc 換出去
執行緒 pool-1-thread-2 正在把資料 123 換出去
執行緒 pool-1-thread-1換回的資料為 123
執行緒 pool-1-thread-2換回的資料為 abc
相關文章
- JUC之Exchanger-多執行緒與高併發執行緒
- Java併發和多執行緒4:使用通用同步工具CountDownLatch實現執行緒等待Java執行緒CountDownLatch
- Java多執行緒20:多執行緒下的其他元件之CountDownLatch、Semaphore、ExchangerJava執行緒元件CountDownLatch
- 多執行緒與併發----Semaphere同步執行緒
- java多執行緒10:併發工具類CountDownLatch、CyclicBarrier和SemaphoreJava執行緒CountDownLatch
- 併發工具類(一)等待多執行緒的CountDownLatch執行緒CountDownLatch
- java多執行緒系列:Semaphore和ExchangerJava執行緒
- Java多執行緒同步工具類之CountDownLatchJava執行緒CountDownLatch
- CountDownLatch 多執行緒同步輔助類用法CountDownLatch執行緒
- 多執行緒和多執行緒同步執行緒
- java 多執行緒CountDownLatchJava執行緒CountDownLatch
- 多執行緒與高併發(二)執行緒安全執行緒
- 併發與多執行緒之執行緒安全篇執行緒
- Java 併發工具類 CountDownLatch、CyclicBarrier、Semaphore、ExchangerJavaCountDownLatch
- 多執行緒與高併發(一)多執行緒入門執行緒
- Java 併發和多執行緒(一) Java併發性和多執行緒介紹[轉]Java執行緒
- java多執行緒詳解(併發,並行,同步)Java執行緒並行
- 【java 多執行緒】多執行緒併發同步問題及解決方法Java執行緒
- java併發程式設計JUC第九篇:CountDownLatch執行緒同步Java程式設計CountDownLatch執行緒
- 併發與多執行緒基礎執行緒
- java多執行緒與併發 - 併發工具類Java執行緒
- java多執行緒系列:CountDownLatchJava執行緒CountDownLatch
- java 多執行緒 CountDownLatch用法Java執行緒CountDownLatch
- java多執行緒與併發 - 執行緒池詳解Java執行緒
- Java併發和多執行緒:序Java執行緒
- Java多執行緒/併發11、執行緒同步通訊:notify、waitJava執行緒AI
- 【多執行緒與高併發】- 執行緒基礎與狀態執行緒
- 10、Java併發性和多執行緒-執行緒安全與不可變性Java執行緒
- 多執行緒與併發----讀寫鎖執行緒
- 併發工具類(四)執行緒間的交換資料 Exchanger執行緒
- 程式與執行緒、同步與非同步、阻塞與非阻塞、併發與並行執行緒非同步並行
- JAVA多執行緒和併發基礎Java執行緒
- JAVA多執行緒併發Java執行緒
- iOS 多執行緒--GCD 序列佇列、併發佇列以及同步執行、非同步執行iOS執行緒GC佇列非同步
- 多執行緒併發:以AQS中acquire()方法為例來分析多執行緒間的同步與協作執行緒AQSUI
- Java多執行緒/併發06、執行緒鎖Lock與ReadWriteLockJava執行緒
- 多執行緒併發篇——如何停止執行緒執行緒
- 多執行緒併發同步問題及解決方案執行緒