Java並發編程工具類 CountDownLatch CyclicBarrier Semaphore使用Demo
CountDownLatch
countDownLatch這個類使一個線程等待其他線程各自執行完畢后再執行。
是通過一個計數器來實現的,計數器的初始值是線程的數量。每當一個線程執行完畢后,計數器的值就-1,當計數器的值為0時,表示所有線程都執行完畢,然后在閉鎖上等待的線程就可以恢復工作了。
CountDownLatch中的方法
//調用await()方法的線程會被掛起,它會等待直到count值為0才繼續執行
public void await() throws InterruptedException { };
//和await()類似,只不過等待一定的時間后count值還沒變為0的話就會繼續執行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
//將count值減1
public void countDown() { };
CountDownLatchDemo
條件改為i<20時,並不會輸出“完結撒花”,因為latch還沒有減到0
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(20);
//條件改為i<20時,並不會輸出“完結撒花”,因為latch還沒有減到0
for (int i = 0; i < 20; i++) {
int index=i;
new Thread(new Runnable() {
@Override
public void run() {
latch.countDown();
System.out.println(index);
}
}).start();
}
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("完結撒花");
}
}
CyclicBarrier
CyclicBarrier可以使一定數量的線程反復地在柵欄位置處匯集。當線程到達柵欄位置時將調用await方法,這個方法將阻塞直到所有線程都到達柵欄位置。如果所有線程都到達柵欄位置,那么柵欄將打開,此時所有的線程都將被釋放,而柵欄將被重置以便下次使用。
- CountDownLatch 是一次性的,CyclicBarrier 是可循環利用的
構造方法
public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)
- parties 是參與線程的個數
- 第二個構造方法有一個 Runnable 參數,這個參數的意思是最后一個到達線程要做的任務
方法
public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException
- 線程調用 await() 表示自己已經到達柵欄
- BrokenBarrierException 表示柵欄已經被破壞,破壞的原因可能是其中一個線程 await() 時被中斷或者超時
Demo
- 初始化線程1,線程1睡眠3秒
- 剩余九個線程到達barrier,但是並不會又輸出
- 三秒后線程1到達,9個線程開始輸出
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(10);
//初始化線程1,線程1睡眠3秒,等待剩余九個線程到達barrier
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.currentThread().sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}).start();
//九個線程先到達barrier
for (int i = 0; i < 9; i++) {
int index=i;
new Thread(new Runnable() {
@Override
public void run() {
try {
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(index);
}
}).start();
}
}
}
//Output,輸出是隨機的
/*
0
6
2
1
8
7
4
3
5*/
Semaphore
Semaphore也是一個線程同步的輔助類,可以維護當前訪問自身的線程個數,並提供了同步機制。使用Semaphore可以控制同時訪問資源的線程個數,例如,實現一個文件允許的並發訪問數。
常用方法
void acquire():從此信號量獲取一個許可,在提供一個許可前一直將線程阻塞,否則線程被中斷。
void release():釋放一個許可,將其返回給信號量。
int availablePermits():返回此信號量中當前可用的許可數。
boolean hasQueuedThreads():查詢是否有線程正在等待獲取。
Demo
- 六個人競爭三個辦事窗口,每個辦事窗口只能容納三個人,輸出如下
package ConcurrentApi;
import java.util.concurrent.Semaphore;
//Output
/*
線程0等到了辦事窗口空閑
辦事窗口剩余量2
線程1等到了辦事窗口空閑
辦事窗口剩余量1
線程2等到了辦事窗口空閑
辦事窗口剩余量0
線程3等到了辦事窗口空閑
辦事窗口剩余量0
線程4等到了辦事窗口空閑
辦事窗口剩余量0
線程5等到了辦事窗口空閑
辦事窗口剩余量0*/
public class SemaphoreDemo {
public static void main(String[] args) {
//初始化3 三個辦事窗口
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 6; i++) {
int index = i;
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
System.out.println("線程"+index+"等到了辦事窗口空閑");
System.out.println("辦事窗口剩余量"+semaphore.availablePermits());
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.currentThread().sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
semaphore.release();
}
}).start();
}
}
}