1.CountDownLatch的用法
public CountDownLatch(int count) { // 參數count爲計數值
...
}
public void await() throws InterruptedException {
// 調用await()方法的線程會被掛起,它會等待直到count值爲0才繼續進行
...
}
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
// 和await()類似,只不過等待一定時間後count值還沒變爲0的話就會繼續執行
...
}
public void countDown() { // 將count值減1
...
}
public class MyCountDownLatch {
public static void main(String[] args){
CountDownLatch latch = new CountDownLatch(2);
for (int i = 0; i < 2; i++) {
new Thread() {
@Override
public void run() {
try {
System.out.println("子線程"+Thread.currentThread().getName()+"正在執行");
Thread.sleep(3000);
System.out.println("子線程"+Thread.currentThread().getName()+"執行完畢");
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
try {
System.out.println("等待2個子線程執行完畢");
latch.await();
System.out.println("2個子線程已經執行完畢");
System.out.println("繼續執行主線程");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
等待2個子線程執行完畢
子線程Thread-1正在執行
子線程Thread-0正在執行
子線程Thread-0執行完畢
子線程Thread-1執行完畢
2個子線程已經執行完畢
繼續執行主線程
2.CyclicBarrier用法
public CyclicBarrier(int parties, Runnable barrierAction) {
...
}
public CyclicBarrier(int parties) {
...
}
參數parties指讓多少個線程或者任務等待至barrier狀態;參數barrierAction爲當這些線程都達到barrier狀態時會執行的內容。public int await() throws InterruptedException, BrokenBarrierException {
...
}
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException,
TimeoutException {
...
}
第一個版本比較常用,用來掛起當前線程,直至所有線程都達到barrier狀態再同時執行後續任務;public class MyCyclicBarrier {
public static void main(String[] args){
CyclicBarrier barrier = new CyclicBarrier(4);
for (int i = 0; i < 4; i++) {
new Thread(new Writer(barrier)).start();
}
System.out.println("主線程執行完畢");
}
static class Writer implements Runnable {
private CyclicBarrier barrier;
public Writer(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
System.out.println("線程" + Thread.currentThread().getName() + "正在寫入數據...");
try {
Thread.sleep(5000);
System.out.println("線程" + Thread.currentThread().getName() + "寫入數據完畢,等待其他線程寫入完畢");
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("所有線程寫入完畢,繼續處理其他任務...");
}
}
}
執行結果爲:
線程Thread-0正在寫入數據...
線程Thread-3正在寫入數據...
主線程執行完畢
線程Thread-2正在寫入數據...
線程Thread-1正在寫入數據...
線程Thread-2寫入數據完畢,等待其他線程寫入完畢
線程Thread-0寫入數據完畢,等待其他線程寫入完畢
線程Thread-3寫入數據完畢,等待其他線程寫入完畢
線程Thread-1寫入數據完畢,等待其他線程寫入完畢
所有線程寫入完畢,繼續處理其他任務...
所有線程寫入完畢,繼續處理其他任務...
所有線程寫入完畢,繼續處理其他任務...
所有線程寫入完畢,繼續處理其他任務...
從上面輸出結果可以看出,每個寫入線程執行完寫操作之後,就在等到其他線程寫入操作完畢public class MyCyclicBarrier2 {
public static void main(String[] args){
CyclicBarrier barrier = new CyclicBarrier(4, new Runnable() {
@Override
public void run() {
System.out.println("當前線程:" + Thread.currentThread().getName());
}
});
for (int i = 0; i < 4; i++) {
new Writer(barrier).start();
}
}
static class Writer extends Thread {
private CyclicBarrier barrier;
public Writer(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
System.out.println("線程" + Thread.currentThread().getName() + "正在寫入數據");
try {
Thread.sleep(5000);
System.out.println("線程" + Thread.currentThread().getName() + "寫入數據完畢,等待其他線程寫入完畢");
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
線程Thread-0正在寫入數據
線程Thread-3正在寫入數據
線程Thread-2正在寫入數據
線程Thread-1正在寫入數據
線程Thread-3寫入數據完畢,等待其他線程寫入完畢
線程Thread-1寫入數據完畢,等待其他線程寫入完畢
線程Thread-0寫入數據完畢,等待其他線程寫入完畢
線程Thread-2寫入數據完畢,等待其他線程寫入完畢
當前線程:Thread-1
可以發現,當4個線程都到達barrier狀態後,會從四個線程中選擇一個線程去執行Runnablepublic class MyCyclicBarrier3 {
public static void main(String[] args){
CyclicBarrier barrier = new CyclicBarrier(4);
for (int i = 0; i < 4; i++) {
if (i < 3) {
new Writer(barrier).start();
} else {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Writer(barrier).start();
}
}
}
static class Writer extends Thread {
private CyclicBarrier barrier;
public Writer(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
System.out.println("線程" + Thread.currentThread().getName() + "正在寫入數據");
try {
Thread.sleep(5000);
System.out.println("線程" + Thread.currentThread().getName() + "寫入數據完畢,等待其他線程寫入完畢");
barrier.await(2000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "所有線程寫入完畢,繼續處理其他任務...");
}
}
}
線程Thread-1正在寫入數據
線程Thread-2正在寫入數據
線程Thread-0正在寫入數據
線程Thread-0寫入數據完畢,等待其他線程寫入完畢
線程Thread-1寫入數據完畢,等待其他線程寫入完畢
線程Thread-2寫入數據完畢,等待其他線程寫入完畢
線程Thread-3正在寫入數據
Thread-1所有線程寫入完畢,繼續處理其他任務...
java.util.concurrent.TimeoutException
Thread-2所有線程寫入完畢,繼續處理其他任務...
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:257)
Thread-0所有線程寫入完畢,繼續處理其他任務...
at com.lucifer.mutil.MyCyclicBarrier3$Writer.run(MyCyclicBarrier3.java:44)
java.util.concurrent.BrokenBarrierException
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at com.lucifer.mutil.MyCyclicBarrier3$Writer.run(MyCyclicBarrier3.java:44)
java.util.concurrent.BrokenBarrierException
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at com.lucifer.mutil.MyCyclicBarrier3$Writer.run(MyCyclicBarrier3.java:44)
線程Thread-3寫入數據完畢,等待其他線程寫入完畢
Thread-3所有線程寫入完畢,繼續處理其他任務...
java.util.concurrent.BrokenBarrierException
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at com.lucifer.mutil.MyCyclicBarrier3$Writer.run(MyCyclicBarrier3.java:44)
public class MyCyclicBarrier4 {
public static void main(String[] args){
CyclicBarrier barrier = new CyclicBarrier(4);
for (int i = 0; i < 4; i++) {
new Writer(barrier).start();
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("CyclicBarrier重用");
for (int i = 0; i < 4; i++) {
new Writer(barrier).start();
}
}
static class Writer extends Thread {
private CyclicBarrier barrier;
public Writer(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
System.out.println("線程" + Thread.currentThread().getName() + "正在寫入數據");
try {
Thread.sleep(2000);
System.out.println("線程" + Thread.currentThread().getName() + "寫入數據完畢,等待其他線程寫入完畢");
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "所有線程寫入完畢,繼續處理其他任務...");
}
}
}
3.Semaphore用法
public Semaphore(int permits) {
...
}
public Semaphore(int permits, boolean fair) {
...
}
下面說一下Semaphore類中比較重要的幾個方法,首先是acquire(),release()方法:public void acquire() throws InterruptedException { // 獲取一個許可
...
}
public void acquire(int permits) throws InterruptedException { // 獲取permits個許可
...
}
public void release() { // 釋放許可
...
}
public void release(int permits) { // 釋放permits個許可
...
}
acquire()用來獲取一個許可,若無許可能夠獲得,則會一直等待,直到獲取許可// 嘗試獲得一個許可,若獲取成功,則立即返回true,若獲取失敗,則立即返回false
public boolean tryAcquire() {}
// 嘗試獲取一個許可,若在指定時間內獲取成功,則立即返回true,否則立即返回false
public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException {}
// 嘗試獲取permits個許可,若在指定時間內獲取成功,則立即返回true,否則立即返回fasle
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException {}
// 嘗試獲取permits個許可,若獲取成功,則立即返回true,否則立即返回false
public boolean tryAcquire(int permits) {}
public class MySemaphore {
public static void main(String[] args){
Semaphore semaphore = new Semaphore(5);
for (int i = 0; i < 8; 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+"佔用一個機器在生產...");
Thread.sleep(2000);
System.out.println("工人"+this.num+"釋放出機器");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
執行結果:工人0佔用一個機器在生產...
工人4佔用一個機器在生產...
工人3佔用一個機器在生產...
工人2佔用一個機器在生產...
工人1佔用一個機器在生產...
工人0釋放出機器
工人5佔用一個機器在生產...
工人2釋放出機器
工人3釋放出機器
工人4釋放出機器
工人1釋放出機器
工人7佔用一個機器在生產...
工人6佔用一個機器在生產...
工人6釋放出機器
工人5釋放出機器
工人7釋放出機器
- CountDownLatch一般用於某個線程A等待若干個其他線程執行完任務後,它才執行
- CyclicBarrier一般用於一組線程互相等待至某個狀態,然後這一組線程再同時執行
- 另外,CountDownLatch是不能重用的,而CyclicBarrier是可以重用的