比如在测试并发时,主线程需要等待其他线程执行完才退出就可以用CountDownLatch来实现了。
@Test
public void testCountDown() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("开始执行,计数减一");
latch.countDown();
try {
Thread.sleep(1000);
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行完毕");
}
}).start();
}
latch.await();
Thread.sleep(2000);
System.out.println("所有都执行完了");
}
比如需要控制线程同时做一些准备工作后,才同时进行接下来的操作,就能用到栅栏了。
@Test
public void testCyclicBarrier() throws BrokenBarrierException, InterruptedException {
CyclicBarrier barrier = new CyclicBarrier(6);
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("开始执行");
try {
Thread.sleep(1000);
// 等待其他线程执行到这一步
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
// 后续执行操作
System.out.println("执行完毕");
}
}).start();
}
barrier.await();
Thread.sleep(1000);
System.out.println("结束");
}
比如有多个阶段的工作都需要进行控制,同时到达后才能触发,就可以用到这个了
@Test
public void testPh() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
Phaser phaser = new Phaser(10){
@Override
protected boolean onAdvance(int phase, int registeredParties) {
System.out.println("========phase:"+phase+"======");
return registeredParties == 0;
}
};
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("开始执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
phaser.arriveAndAwaitAdvance();
System.out.println("完成执行1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
phaser.arriveAndAwaitAdvance();
System.out.println("完成执行2");
latch.countDown();
}
}).start();
}
latch.await();
System.out.println("全部执行完");
}
有一个场景,需要测试并发场景捡瓶子时的性能,捡瓶子前需要先按概率抽取要捡哪个时间段的瓶子(准备工作),想要真正第模拟捡瓶子的性能,就需要控制所有线程能同时触发捡这个功能,而不是同时从概率抽取开始,所以就需要栅栏来控制了,概率抽取是第一个阶段的工作,捡瓶子是第二个阶段的工作,接下来才能让主线程结束。
CountDownLatch:通知主线程,测试线程已经完成操作了
Phaser:完成两个阶段的栅栏控制
@Test
public void getRandomBottlePharse() throws InterruptedException, BrokenBarrierException {
String userId = "88888";
Phaser phaser = new Phaser(50){
@Override
protected boolean onAdvance(int phase, int registeredParties) {
System.out.println("==============第"+phase+"阶段完成==============");
return registeredParties == 0;
}
};
CountDownLatch latch = new CountDownLatch(50);
for (int i = 0; i < 50; i++) {
new Thread(new Runnable() {
@Override
public void run() {
CollectBottleRate collectBottleRate = new CollectBottleRate();
collectBottleRate.setLastDay(60);
collectBottleRate.setLastWeek(20);
collectBottleRate.setLastMonth(15);
collectBottleRate.setLastHalfYear(5);
int day = collectBottleRate.lotteryBottleDay();
System.out.println("等待所有线程准备,day:"+day+", count:" + phaser.getArrivedParties());
// 栅栏:等待准备
phaser.arriveAndAwaitAdvance();
Bottle b = randomBottle.getRandomBottle(userId, day);
System.out.println("捡到瓶子:" + b.toString());
// 主线程等待执行完
phaser.arriveAndAwaitAdvance();
latch.countDown();
}
}).start();
}
latch.await();
System.out.println("全部执行完了");
}
CountDownLatch:同样通知主线程测试线程的执行情况
CyclicBarrier:只对第一个阶段进行栅栏控制
@Test
public void getRandomBottle() throws InterruptedException, BrokenBarrierException {
String userId = "2088612750326750";
CyclicBarrier barrier = new CyclicBarrier(50);
CountDownLatch latch = new CountDownLatch(50);
for (int i = 0; i < 50; i++) {
new Thread(new Runnable() {
@Override
public void run() {
CollectBottleRate collectBottleRate = new CollectBottleRate();
collectBottleRate.setLastDay(60);
collectBottleRate.setLastWeek(20);
collectBottleRate.setLastMonth(15);
collectBottleRate.setLastHalfYear(5);
int day = collectBottleRate.lotteryBottleDay();
System.out.println("等待所有线程准备, count:" + barrier.getNumberWaiting());
try {
// 栅栏:等待准备
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
Bottle b = randomBottle.getRandomBottle(userId, day);
System.out.println("捡到瓶子:" + b.toString());
// 主线程等待执行完
latch.countDown();
}
}).start();
}
latch.await();
System.out.println("全部执行完了");
}
http://www.jasongj.com/java/thread_communication/