CountDownLatch,Semaphore,CyclicBarrier 都是在 JUC 下包含了一些常用的同步工具類,其實將其放在一起介紹印象會更加深刻,由於對其瞭解使用的先後順序,造成並沒有一起來介紹。
CountDownLatch:
當一個線程調用await方法時,就會阻塞當前線程。每當有線程調用一次 countDown 方法時,計數就會減 1。當 count 的值等於 0 的時候,被阻塞的線程纔會繼續運行。
CountDownLatch 的同步使用方法
Semaphore:
Semaphore 信號量,用來控制同一時間,資源可被訪問的線程數量,一般可用於流量的控制。
Semaphore 控制線程併發量
CyclicBarrier:
CyclicBarrier 是多個線程互相等待,一直到指定線程數到達指定位置。
1、CyclicBarrier 有兩個構造函數,
/**
* Creates a new {@code CyclicBarrier} that will trip when the
* given number of parties (threads) are waiting upon it, and which
* will execute the given barrier action when the barrier is tripped,
* performed by the last thread entering the barrier.
*
* @param parties the number of threads that must invoke {@link #await}
* before the barrier is tripped
* @param barrierAction the command to execute when the barrier is
* tripped, or {@code null} if there is no action
* @throws IllegalArgumentException if {@code parties} is less than 1
*/
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
/**
* Creates a new {@code CyclicBarrier} that will trip when the
* given number of parties (threads) are waiting upon it, and
* does not perform a predefined action when the barrier is tripped.
*
* @param parties the number of threads that must invoke {@link #await}
* before the barrier is tripped
* @throws IllegalArgumentException if {@code parties} is less than 1
*/
public CyclicBarrier(int parties) {
this(parties, null);
}
根據源碼上面註釋,public CyclicBarrier(int parties) 當指定線程數到達等待的地方,所有線程往下走。 public CyclicBarrier(int parties, Runnable barrierAction) 這個方法當指定線程數到達等待的地方 ,先執行構造函數裏面的Runnable 的run方法,所有線程再繼續往下走。
1、public CyclicBarrier(int parties) 構造函數
public class CyclicBarrierTest {
public static void main(String[] args) throws InterruptedException {
CyclicBarrier barrier = new CyclicBarrier(3);
SynchronizeRunner runner1 = new SynchronizeRunner("barrierq1", barrier);
SynchronizeRunner runner2 = new SynchronizeRunner("barrierq2", barrier);
SynchronizeRunner runner3 = new SynchronizeRunner("barrierq3", barrier);
new Thread(runner1).start();
new Thread(runner2).start();
new Thread(runner3).start();
Thread.currentThread().join(1000);
}
}
class SynchronizeRunner implements Runnable{
private String name;
private CyclicBarrier cyclicBarrier;
public SynchronizeRunner(String name, CyclicBarrier cyclicBarrier) {
this.name = name;
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
System.out.println(name+":開始進入run方法");
cyclicBarrier.await();
System.out.println(name+":跳過await方法");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
執行結果:
barrierq3:開始進入run方法
barrierq1:開始進入run方法
barrierq2:開始進入run方法
barrierq2:跳過await方法
barrierq1:跳過await方法
barrierq3:跳過await方法
2、 public CyclicBarrier(int parties, Runnable barrierAction) 構造函數
public class CyclicBarrierTest {
public static void main(String[] args) throws InterruptedException {
CyclicBarrier barrier = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
try {
System.out.println("CyclicBarrier 構造器中的run 休眠之前");
TimeUnit.SECONDS.sleep(2);
System.out.println("CyclicBarrier 構造器中的run 休眠之後");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
SynchronizeRunner runner1 = new SynchronizeRunner("barrierq1", barrier);
SynchronizeRunner2 runner2 = new SynchronizeRunner2("barrierq2", barrier);
SynchronizeRunner runner3 = new SynchronizeRunner("barrierq3", barrier);
new Thread(runner1).start();
new Thread(runner2).start();
new Thread(runner3).start();
Thread.currentThread().join(1000);
}
}
class SynchronizeRunner implements Runnable{
private String name;
private CyclicBarrier cyclicBarrier;
public SynchronizeRunner(String name, CyclicBarrier cyclicBarrier) {
this.name = name;
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
System.out.println(name+":開始進入run方法");
cyclicBarrier.await();
System.out.println(name+":跳過await方法");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
class SynchronizeRunner2 implements Runnable {
private String name;
private CyclicBarrier cyclicBarrier;
public SynchronizeRunner2(String name, CyclicBarrier cyclicBarrier) {
this.name = name;
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
System.out.println(name + ":開始進入SynchronizeRunner2類中的run方法");
cyclicBarrier.await();
System.out.println(name + ":跳過開始進入SynchronizeRunner2類中的await方法");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
執行結果:
barrierq3:開始進入run方法
barrierq1:開始進入run方法
barrierq2:開始進入SynchronizeRunner2類中的run方法
CyclicBarrier 構造器中的run 休眠之前
CyclicBarrier 構造器中的run 休眠之後
barrierq3:跳過await方法
barrierq2:跳過開始進入SynchronizeRunner2類中的await方法
barrierq1:跳過await方法
由2結果可知,await不一定必須是同一個類,只要指定線程到達對應地方就可以了。
如果看了可能會發現CyclicBarrier 和 CountDownLatch 非常相似,CyclicBarrier 是多個線程相互等待。CountDownLatch 是一個線程等待多個線程。