轉載自:http://blog.csdn.net/jackyechina/article/details/52931453
區別
- CountDownLatch 使一個線程A或是組線程A等待其它線程執行完畢後,一個線程A或是組線程A才繼續執行。CyclicBarrier:一組線程使用await()指定barrier,所有線程都到達各自的barrier後,再同時執行各自barrier下面的代碼。Semaphore:是用來控制同時訪問特定資源的線程數量,它通過協調各個線程,以保證合理的使用公共資源
- CountDownLatch是減計數方式,計數==0時釋放所有等待的線程;CyclicBarrier是加計數方式,計數達到構造方法中參數指定的值時釋放所有等待的線程。Semaphore,每次semaphore.acquire(),獲取一個資源,每次semaphore.acquire(n),獲取n個資源,當達到semaphore 指定資源數量時就不能再訪問線程處於阻塞,必須等其它線程釋放資源,semaphore.relase()每次資源一個資源,semaphore.relase(n)每次資源n個資源。
- CountDownLatch當計數到0時,計數無法被重置;CyclicBarrier計數達到指定值時,計數置爲0重新開始。
- CountDownLatch每次調用countDown()方法計數減一,調用await()方法只進行阻塞,對計數沒任何影響;CyclicBarrier只有一個await()方法,調用await()方法計數加1,若加1後的值不等於構造方法的值,則線程阻塞。
- CountDownLatch、CyclikBarrier、Semaphore 都有一個int類型參數的構造方法。CountDownLatch、CyclikBarrier這個值作爲計數用,達到該次數即釋放等待的線程,而Semaphore
中所有acquire獲取到的資源達到這個數,會使得其它線程阻塞。
- CountDownLatch與CyclikBarrier兩者的共同點是都具有await()方法,並且執行此方法會引起線程的阻塞,達到某種條件才能繼續執行(這種條件也是兩者的不同)。Semaphore,acquire方獲取的資源達到最大數量時,線程再次acquire獲取資源時,也會使線程處於阻塞狀態。CountDownLatch與CyclikBarrier兩者的共同點是都具有await()方法,並且執行此方法會引起線程的阻塞,達到某種條件才能繼續執行(這種條件也是兩者的不同)。Semaphore,acquire方獲取的資源達到最大數量時,線程再次acquire獲取資源時,也會使線程處於阻塞狀態。CountDownLatch、CyclikBarrier、Semaphore 都有一個int類型參數的構造方法。
- CountDownLatch、CyclikBarrier、Semaphore 都有一個int類型參數的構造方法。
CountDownLatch、CyclicBarrier和Semaphore使用場景
CountDownLatch
由於CountDownLatch有個countDown()方法並且countDown()不會引起阻塞,所以CountDownLatch可以應用於主線程等待所有子線程結束後再繼續執行的情況。具體使用方式爲new一個構造參數爲subThread數目的CountDownLatch,啓動所有子線程後主線程await(),在每個子線程的最後執行countDown(),這樣當所有子線程執行完後計數減爲0,主線程釋放等待繼續執行。比如賽跑,每個運動員看做一個子線程,裁判就是主線程,裁判發令(設置一個值爲1的計數器,發令之前所有子線程await等待命令,裁判員發令讓計數置爲0,所有子線程同時開跑)所有運動員開跑後,需要等待所有人跑完再統計成績(設置一個值爲運動員數目的計數器,所有運動員開跑後裁判await被阻塞,每個運動員跑完的時候countDown()一下,所有運動員跑完計數達到0,裁判釋放阻塞開始計分)。- public class CountDownLatchCase {
- public static void main(String args[]){
- //主線程爲裁判,子線程爲運動員
- final CountDownLatch operatorNum=new CountDownLatch(6);
- for(int i=0;i<6;i++){
- new Thread(new Runnable() {
- @Override
- public void run() {
- Long s=System.currentTimeMillis();
- Random random=new Random();
- try {
- Thread.sleep(random.nextInt(10000));
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- Long time=System.currentTimeMillis()-s;
- System.out.println(String.format(”運動員%s跑完,花了%s”, Thread.currentThread().getName(),time));
- //一個運動員跑完了
- operatorNum.countDown();
- }
- }).start();
- }
- try {
- operatorNum.await();
- System.out.println(String.format(”所有運行員都跑完了,裁判%s可宣佈結果啦!”, Thread.currentThread().getName()));
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
public class CountDownLatchCase {
public static void main(String args[]){
//主線程爲裁判,子線程爲運動員
final CountDownLatch operatorNum=new CountDownLatch(6);
for(int i=0;i<6;i++){
new Thread(new Runnable() {
@Override
public void run() {
Long s=System.currentTimeMillis();
Random random=new Random();
try {
Thread.sleep(random.nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
Long time=System.currentTimeMillis()-s;
System.out.println(String.format("運動員%s跑完,花了%s", Thread.currentThread().getName(),time));
//一個運動員跑完了
operatorNum.countDown();
}
}).start();
}
try {
operatorNum.await();
System.out.println(String.format("所有運行員都跑完了,裁判%s可宣佈結果啦!", Thread.currentThread().getName()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
CyclicBarrier
- /**
- * 各省數據獨立,分庫存偖。爲了提高計算性能,統計時採用每個省開一個線程先計算單省結果,最後彙總。
- *
- * @author guangbo email:[email protected]
- *
- */
- public class Total {
- // private ConcurrentHashMap result = new ConcurrentHashMap();
- public static void main(String[] args) {
- TotalService totalService = new TotalServiceImpl();
- CyclicBarrier barrier = new CyclicBarrier(5,
- new TotalTask(totalService));
- // 實際系統是查出所有省編碼code的列表,然後循環,每個code生成一個線程。
- new BillTask(new BillServiceImpl(), barrier, “北京”).start();
- new BillTask(new BillServiceImpl(), barrier, “上海”).start();
- new BillTask(new BillServiceImpl(), barrier, “廣西”).start();
- new BillTask(new BillServiceImpl(), barrier, “四川”).start();
- new BillTask(new BillServiceImpl(), barrier, “黑龍江”).start();
- }
- }
- /**
- * 主任務:彙總任務
- */
- class TotalTask implements Runnable {
- private TotalService totalService;
- TotalTask(TotalService totalService) {
- this.totalService = totalService;
- }
- public void run() {
- // 讀取內存中各省的數據彙總,過程略。
- totalService.count();
- System.out.println(”=======================================”);
- System.out.println(”開始全國彙總”);
- }
- }
- /**
- * 子任務:計費任務
- */
- class BillTask extends Thread {
- // 計費服務
- private BillService billService;
- private CyclicBarrier barrier;
- // 代碼,按省代碼分類,各省數據庫獨立。
- private String code;
- BillTask(BillService billService, CyclicBarrier barrier, String code) {
- this.billService = billService;
- this.barrier = barrier;
- this.code = code;
- }
- public void run() {
- System.out.println(”開始計算–” + code + “省–數據!”);
- billService.bill(code);
- // 把bill方法結果存入內存,如ConcurrentHashMap,vector等,代碼略
- System.out.println(code + ”省已經計算完成,並通知彙總Service!”);
- try {
- // 通知barrier已經完成
- barrier.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (BrokenBarrierException e) {
- e.printStackTrace();
- }
- }
- }
/**
* 各省數據獨立,分庫存偖。爲了提高計算性能,統計時採用每個省開一個線程先計算單省結果,最後彙總。
*
* @author guangbo email:[email protected]
*
*/
public class Total {
// private ConcurrentHashMap result = new ConcurrentHashMap();
public static void main(String[] args) {
TotalService totalService = new TotalServiceImpl();
CyclicBarrier barrier = new CyclicBarrier(5,
new TotalTask(totalService));
// 實際系統是查出所有省編碼code的列表,然後循環,每個code生成一個線程。
new BillTask(new BillServiceImpl(), barrier, "北京").start();
new BillTask(new BillServiceImpl(), barrier, "上海").start();
new BillTask(new BillServiceImpl(), barrier, "廣西").start();
new BillTask(new BillServiceImpl(), barrier, "四川").start();
new BillTask(new BillServiceImpl(), barrier, "黑龍江").start();
}
}
/**
* 主任務:彙總任務
*/
class TotalTask implements Runnable {
private TotalService totalService;
TotalTask(TotalService totalService) {
this.totalService = totalService;
}
public void run() {
// 讀取內存中各省的數據彙總,過程略。
totalService.count();
System.out.println("=======================================");
System.out.println("開始全國彙總");
}
}
/**
* 子任務:計費任務
*/
class BillTask extends Thread {
// 計費服務
private BillService billService;
private CyclicBarrier barrier;
// 代碼,按省代碼分類,各省數據庫獨立。
private String code;
BillTask(BillService billService, CyclicBarrier barrier, String code) {
this.billService = billService;
this.barrier = barrier;
this.code = code;
}
public void run() {
System.out.println("開始計算--" + code + "省--數據!");
billService.bill(code);
// 把bill方法結果存入內存,如ConcurrentHashMap,vector等,代碼略
System.out.println(code + "省已經計算完成,並通知彙總Service!");
try {
// 通知barrier已經完成
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
Semaphore
- public class SemaphoreCase {
- private static final int THREAD_COUNT = 30;
- private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);
- private static Semaphore s = new Semaphore(10);
- public static void main(String[] args) {
- for (int i = 0; i < THREAD_COUNT; i++) {
- threadPool.execute(new Runnable() {
- @Override
- public void run() {
- try {
- s.acquire();
- System.out.println(”save data”);
- s.release();
- } catch (InterruptedException e) {
- }
- }
- });
- }
- threadPool.shutdown();
- }
- }
public class SemaphoreCase {
private static final int THREAD_COUNT = 30;
private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);
private static Semaphore s = new Semaphore(10);
public static void main(String[] args) {
for (int i = 0; i < THREAD_COUNT; i++) {
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
s.acquire();
System.out.println("save data");
s.release();
} catch (InterruptedException e) {
}
}
});
}
threadPool.shutdown();
}
}
注意:- release函數和acquire並沒有要求一定是同一個線程都調用,可以A線程申請資源,B線程釋放資源;
- 調用release函數之前並沒有要求一定要先調用acquire函數。