CountDownLatch
用來同步一個或多個任務。
CountDownLatch
使用計數器來實作,通過構造器初始化計數器的初始數量,當計數器計數為0時,被
await()
阻塞的線程将繼續執行
public CountDownLatch(int count)
主要使用方法
//調用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() { };
示例(别處借來):
public class CountDownLatchTest {
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(2);
System.out.println("主線程開始執行…… ……");
//第一個子線程執行
ExecutorService es1 = Executors.newSingleThreadExecutor();
es1.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
System.out.println("子線程:"+Thread.currentThread().getName()+"執行");
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
}
});
es1.shutdown();
//第二個子線程執行
ExecutorService es2 = Executors.newSingleThreadExecutor();
es2.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子線程:"+Thread.currentThread().getName()+"執行");
latch.countDown();
}
});
es2.shutdown();
System.out.println("等待兩個線程執行完畢…… ……");
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("兩個子線程都執行完畢,繼續執行主線程");
}
}
CountDownLatch
隻能被觸發一次,不能被重置。如果需要重置可使用
CyclicBarrier
CyclicBarrier
CountDownLatch
的可重置計數器版本。
不同點:
- 可通過
方法去重置計數器reset()
- 可以向
提供一個“栅欄動作”,它是一個CylicBarrier
,當計數器為0時,自動執行。Runnable
-
是當計數器為0時,被阻塞的線程可繼續執行代碼,CountDownLatch
是當所有線程都到達CyclicBarrier
(栅欄處)時,所有線程才可以繼續執行代碼,此時await()
也會在CyclicBarrier
方法中重置計數器。nextGeneration()
示例:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
public class Horse implements Runnable {
private static int counter = 0;
private final int id = counter++;
private int strides = 0;
private static Random random = new Random(47);
private static CyclicBarrier barrier;
public Horse(CyclicBarrier b) {
barrier = b;
}
public synchronized int getStrides() {
return strides;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
synchronized (this) {
strides += random.nextInt(3);
}
barrier.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
public String toString() {
return "Horse" + id + " ";
}
public String tracks() {
StringBuilder s = new StringBuilder();
for (int i = 0; i < getStrides(); i++) {
s.append("*");
}
s.append(id);
return s.toString();
}
}
class HorseRace {
static final int FINISH_LINE = 75;
private List<Horse> horses = new ArrayList<>();
private ExecutorService exec = Executors.newCachedThreadPool();
private CyclicBarrier barrier;
public HorseRace(int nHorses, final int pause) {
barrier = new CyclicBarrier(nHorses, new Runnable() {
@Override
public void run() {
StringBuilder s = new StringBuilder();
for (int i = 0; i < FINISH_LINE; i++) {
s.append("=");
}
System.out.println(s);
horses.forEach(temp -> System.out.println(temp.tracks()));
horses.stream().anyMatch(temp -> {
if (temp.getStrides() >= FINISH_LINE) {
System.out.println(temp + "won!");
exec.shutdownNow();
return true;
}
return false;
});
try {
TimeUnit.MILLISECONDS.sleep(pause);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
for (int i = 0; i < nHorses; i++) {
Horse horse = new Horse(barrier);
horses.add(horse);
exec.execute(horse);
}
}
public static void main(String[] args) {
int nHorses = 7;
int pause = 200;
if (args.length > 0) {
int n = new Integer(args[0]);
nHorses = n > 0 ? n : nHorses;
}
if (args.length > 1) {
int p = new Integer(args[1]);
pause = p > -1 ? p : pause;
}
new HorseRace(nHorses,pause);
}
}
這是一個模拟的賽馬遊戲,開始所有馬都會被阻塞,直到所有馬都走了一步。同時
CyclicBarrier
重置計數器,所有馬走了下一步後再次被阻塞。循環此類操作,直至有一匹馬到達終點,中斷所有線程。