CountDownLatch(線程計數(shù)器 )
CountDownLatch 類位于java.util.concurrent 包下干像,利用它可以實現(xiàn)類似計數(shù)器的功能驰弄。比如有一個任務(wù)A,它要等待其他4 個任務(wù)執(zhí)行完畢之后才能執(zhí)行什乙,此時就可以利用CountDownLatch來實現(xiàn)這種功能了已球。
final CountDownLatch latch = new CountDownLatch( 2 );
new Thread()
{
public void run()
{
System.out.println( "子線程" + Thread.currentThread().getName() + "正在執(zhí)行" );
Thread.sleep( 3000 );
System.out.println( "子線程" + Thread.currentThread().getName() + "執(zhí)行完畢" );
latch.countDown();
};
}.start();
new Thread()
{
public void run()
{
System.out.println( "子線程" + Thread.currentThread().getName() + "正在執(zhí)行" );
Thread.sleep( 3000 );
System.out.println( "子線程" + Thread.currentThread().getName() + "執(zhí)行完畢" );
latch.countDown();
};
}.start();
System.out.println( "等待2 個子線程執(zhí)行完畢..." );
latch.await();
System.out.println( "2 個子線程已經(jīng)執(zhí)行完畢" );
System.out.println( "繼續(xù)執(zhí)行主線程" );
}
CyclicBarrier(回環(huán)柵欄-等待至barrier 狀態(tài)再全部同時執(zhí)行)
字面意思回環(huán)柵欄智亮,通過它可以實現(xiàn)讓一組線程等待至某個狀態(tài)之后再全部同時執(zhí)行。叫做回環(huán)因為當(dāng)所有等待線程都被釋放以后阔蛉,CyclicBarrier 可以被重用状原。我們暫且把這個狀態(tài)就叫做barrier,當(dāng)調(diào)用await()方法之后颠区,線程就處于barrier 了。
CyclicBarrier 中最重要的方法就是await 方法器贩,它有2 個重載版本:
- public int await():用來掛起當(dāng)前線程朋截,直至所有線程都到達(dá)barrier 狀態(tài)再同時執(zhí)行后續(xù)任務(wù);
- public int await(long timeout, TimeUnit unit):讓這些線程等待至一定的時間唆姐,如果還有線程沒有到達(dá)barrier 狀態(tài)就直接讓到達(dá)barrier 的線程執(zhí)行后續(xù)任務(wù)廓八。
具體使用如下胆描,另外CyclicBarrier 是可以重用的仗阅。
public static void main( String[] args )
{
int n = 4;
CyclicBarrier barrier = new CyclicBarrier(n);
for ( int i = 0; i < N; i++ )
new Writer( barrier ).start();
}
static class Writer extends Thread {
private CyclicBarrier cyclicBarrier;
public Writer( CyclicBarrier cyclicBarrier )
{
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run()
{
try {
Thread.sleep( 5000 ); /* 以睡眠來模擬線程需要預(yù)定寫入數(shù)據(jù)操作 */
System.out.println( " 線程" + Thread.currentThread().getName() + " 寫入數(shù)據(jù)完畢减噪,等待其他線程寫入完畢" );
cyclicBarrier.await();
} catch ( InterruptedException e ) {
e.printStackTrace();
}catch ( BrokenBarrierException e ) {
e.printStackTrace();
}
System.out.println( "所有線程寫入完畢车吹,繼續(xù)處理其他任務(wù),比如數(shù)據(jù)操作" );
}
}
Semaphore(信號量-控制同時訪問的線程個數(shù))
Semaphore 翻譯成字面意思為 信號量朝卒,Semaphore 可以控制同時訪問的線程個數(shù)乐埠,通過acquire() 獲取一個許可,如果沒有就等待瑞眼,而 release() 釋放一個許可棵逊。
Semaphore 類中比較重要的幾個方法:
- public void acquire(): 用來獲取一個許可,若無許可能夠獲得辆影,則會一直等待,直到獲得許可锯蛀。
- public void acquire(int permits):獲取permits 個許可
- public void release() { } :釋放許可键菱。注意,在釋放許可之前拭抬,必須先獲獲得許可侵蒙。
- public void release(int permits) { }:釋放permits 個許可上面4 個方法都會被阻塞,如果想立即得到執(zhí)行結(jié)果算凿,可以使用下面幾個方法。
- public boolean tryAcquire():嘗試獲取一個許可婚夫,若獲取成功署鸡,則立即返回true,若獲取失敗靴庆,則立即返回false
- public boolean tryAcquire(long timeout, TimeUnit unit):嘗試獲取一個許可炉抒,若在指定的時間內(nèi)獲取成功,則立即返回true焰薄,否則則立即返回false
- public boolean tryAcquire(int permits):嘗試獲取permits 個許可蛤奥,若獲取成功,則立即返回true凡桥,若獲取失敗,則立即返回false
- public boolean tryAcquire(int permits, long timeout, TimeUnit unit): 嘗試獲取permits個許可啊掏,若在指定的時間內(nèi)獲取成功衰猛,則立即返回true,否則則立即返回false
- 還可以通過availablePermits()方法得到可用的許可數(shù)目娜睛。
例子:若一個工廠有5 臺機(jī)器卦睹,但是有8 個工人,一臺機(jī)器同時只能被一個工人使用障斋,只有使用完了,其他工人才能繼續(xù)使用垃环。那么我們就可以通過Semaphore 來實現(xiàn):
int n = 8; /* 工人數(shù) */
Semaphore semaphore = new Semaphore(5); /* 機(jī)器數(shù)目 */
for(int i = 0; i < N; i++) new Worker(i, semaphore).start();
}
static class Worker extends Thread
{
private int num;
private Semaphore semaphore;
public Worker(int num, Semaphore semaphore)
{
this.num = num;
this.semaphore = semaphore;
}@
Override
public void run()
{
try
{
semaphore.acquire();
System.out.println("工人" + this.num + "占用一個機(jī)器在生產(chǎn)...");
Thread.sleep(2000);
System.out.println("工人" + this.num + "釋放出機(jī)器");
semaphore.release();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
CountDownLatch 和CyclicBarrier 都能夠?qū)崿F(xiàn)線程之間的等待遂庄,只不過它們側(cè)重點不同:
CountDownLatch 一般用于某個線程A 等待若干個其他線程執(zhí)行完任務(wù)之后,它才執(zhí)行;而CyclicBarrier 一般用于一組線程互相等待至某個狀態(tài)只磷,然后這一組線程再同時執(zhí)行;
另外泌绣,CountDownLatch 是不能夠重用的预厌,而CyclicBarrier 是可以重用的。
Semaphore 其實和鎖有點類似苗沧,它一般用于控制對某組資源的訪問權(quán)限炭晒。