1. 閉鎖:CountDownLatch
1.1 使用場景
若有多條線程,其中一條線程需要等到其他所有線程準備完所需的資源後才能運行,這樣的情況可以使用閉鎖。
1.2 代碼實現
// 初始化閉鎖,並設置資源個數
CountDownLatch latch = new CountDownLatch(2);
Thread t1 = new Thread( new Runnable(){
public void run(){
// 加載資源1
加載資源的代碼……
// 本資源加載完後,閉鎖-1
latch.countDown();
}
} ).start();
Thread t2 = new Thread( new Runnable(){
public void run(){
// 加載資源2
資源加載代碼……
// 本資源加載完後,閉鎖-1
latch.countDown();
}
} ).start();
Thread t3 = new Thread( new Runnable(){
public void run(){
// 本線程必須等待所有資源加載完後才能執行
latch.await();
// 當閉鎖數量爲0時,await返回,執行接下來的任務
任務代碼……
}
} ).start();
2. 同步屏障:CyclicBarrier
2.1 使用場景
若有多條線程,他們到達屏障時將會被阻塞,只有當所有線程都到達屏障時才能打開屏障,所有線程同時執行,若有這樣的需求可以使用同步屏障。此外,當屏障打開的同時還能指定執行的任務。
2.2 閉鎖 與 同步屏障 的區別
- 閉鎖只會阻塞一條線程,目的是爲了讓該條任務線程滿足條件後執行;
- 而同步屏障會阻塞所有線程,目的是爲了讓所有線程同時執行(實際上並不會同時執行,而是儘量把線程啓動的時間間隔降爲最少)。
2.3 代碼實現
// 創建同步屏障對象,並制定需要等待的線程個數 和 打開屏障時需要執行的任務
CyclicBarrier barrier = new CyclicBarrier(3,new Runnable(){
public void run(){
//當所有線程準備完畢後觸發此任務
}
});
// 啓動三條線程
for( int i=0; i<3; i++ ){
new Thread( new Runnable(){
public void run(){
// 等待,(每執行一次barrier.await,同步屏障數量-1,直到爲0時,打開屏障)
barrier.await();
// 任務
任務代碼……
}
} ).start();
}
3. 信號量:Semaphore
3.1 使用場景
若有m個資源,但有n條線程(n>m),因此同一時刻只能允許m條線程訪問資源,此時可以使用Semaphore控制訪問該資源的線程數量。
3.2 代碼實現
// 創建信號量對象,並給予3個資源
Semaphore semaphore = new Semaphore(3);
// 開啓10條線程
for ( int i=0; i<10; i++ ) {
new Thread( new Runnbale(){
public void run(){
// 獲取資源,若此時資源被用光,則阻塞,直到有線程歸還資源
semaphore.acquire();
// 任務代碼
……
// 釋放資源
semaphore.release();
}
} ).start();
}