CyclicBarrier和CountDownLatch 都位于java.util.concurrent 这个包下
总结:
CountDownLatch 主要用来解决一个线程等待多个线程的场景,可以类比旅游团团长要等待所有游客到齐才能去下一个景点。
而 CyclicBarrier 是一组线程之间的相互等待,可以类比几个驴友之间的不离不弃,共同到达某个地方,再继续出发,这样反复。
1、CountDownLatch实现并行处理最后汇总结果的功能
package day03.part3;
import java.util.concurrent.CountDownLatch;
/**
* 向下减的门闩
* 实现并行处理最后汇总结果的功能
*
* 以 汽车生产为例
* @author xzq
*/
public class CountDownLatchTest01 {
public static void main(String[] args) throws InterruptedException {
final CountDownLatch cdl=new CountDownLatch(3);
String threadName = Thread.currentThread().getName()+":";
//创建3条线程去做这三件事
new Thread("线程1:"){
@Override
public void run() {
try {
productMotor();
cdl.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread("线程2:"){
@Override
public void run() {
try {
productShell();
cdl.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread("线程3:"){
@Override
public void run() {
try {
productTyre();
cdl.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
//线程4为4S店派到生产厂家的监视者
/*new Thread("线程4:"){
@Override
public void run() {
try {
//可以有多个线程对其进行await
cdl.await();
System.out.println(Thread.currentThread().getName()+"已经生产好了一辆汽车的所有部件了!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();*/
//等待汽车各个部分生产完毕
cdl.await();
System.out.println(threadName+"开始组装汽车……");
//模拟组装生产汽车需要1秒
Thread.sleep(1000);
System.out.println(threadName+"汽车生产完毕,运到销售中心销售。");
}
private static void productMotor() throws InterruptedException{
String threadName = Thread.currentThread().getName();
System.out.println(threadName+"开始生产发动机……");
//生产发动机需要5秒
Thread.sleep(5_000);
System.out.println(threadName+"发动机已生产完毕!");
}
private static void productShell() throws InterruptedException{
String threadName = Thread.currentThread().getName();
System.out.println(threadName+"开始生产汽车外壳……");
//生产汽车外壳需要3秒
Thread.sleep(3_000);
System.out.println(threadName+"汽车外壳已生产完毕!");
}
private static void productTyre() throws InterruptedException{
String threadName = Thread.currentThread().getName();
System.out.println(threadName+"开始生产轮胎……");
//生产汽车轮胎需要1秒
Thread.sleep(1_000);
System.out.println(threadName+"轮胎已生产完毕!");
}
}
2、CountDownLatch实现线程之间的通信
package day03.part3;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
/**
* 向下减的门闩
* 实现线程之间的通信
*
* taobao examination
* 实现一个容器,提供两个方法,add和size
* 写两个线程,线程1添加10个元素到容器中,
* 线程2实现监控元素的个数,当个数到5个时,
* 线程2给出提示并结束
*
* 这里使用CountDownLatch
* 解决这个需求
*
* @author xzq
*/
public class CountDownLatchTest02 {
public static void main(String[] args) {
final Box_5 box=new Box_5();
final CountDownLatch latch=new CountDownLatch(1);
new Thread("线程2"){
@Override
public void run() {
try {
System.out.println("线程2:开始执行");
if(box.size()!=5){
latch.await();
}
System.out.println("线程2:执行完毕!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread("线程1"){
@Override
public void run() {
try {
System.out.println("线程1:开始执行");
for(int i=1;i<=10;i++){
box.add(new Object());
System.out.println("线程1:add第"+i+"个元素");
if(box.size()==5){
latch.countDown();
System.out.println("线程1:已经有5个元素啦!");
}
Thread.sleep(1_000);
}
System.out.println("线程1:执行完毕!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
/**
* 加上volatile后使box的修改可以得到通知
*
* @author Peter
*/
class Box_5{
private volatile List<Object> box=new ArrayList<>();
public void add(Object element){
box.add(element);
}
public int size(){
return box.size();
}
}
3、CountDownLatchAPI的使用讲解
package day03.part3;
import java.util.concurrent.CountDownLatch;
/**
* 向下减的门闩
* API的使用讲解
*
* @author xzq
*/
public class CountDownLatchTest03 {
public static void main(String[] args) throws InterruptedException {
final CountDownLatch cdl=new CountDownLatch(1);//为0时、为-1时
new Thread("子线程:"){
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName+"开始造原子弹……");
//做造原子弹需要做20秒
try {
Thread.sleep(20_000);
cdl.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName+"原子弹制造完毕!");
}
}.start();
//主线程去等待子线程做完某事在往下执行
System.out.println("主线程:开始等待子线程……");
//如果先countDown再进行await,那么就没有效果
// cdl.countDown();
cdl.await();
//await的效果不能叠加
// cdl.await();
//设置超时时间,超过这个时间就不再等待了
// System.out.println("主线程:我只等2秒,2秒后还造不出原子弹,我就不等了!");
// cdl.await(2, TimeUnit.SECONDS);
// System.out.println("主线程:我已经等了2秒了,还没造出原子弹,不等了,开始打仗吧!");
System.out.println("主线程:执行完毕!");
}
}
4、CountDownLatch对中断的处理
package day03.part3;
import java.util.concurrent.CountDownLatch;
/**
* 向下减的门闩
* API的使用讲解
* 对中断的处理
* @author xzq
*/
public class CountDownLatchTest04 {
public static void main(String[] args) {
final Thread mainThread=Thread.currentThread();
final CountDownLatch cdl=new CountDownLatch(1);
new Thread("子线程:"){
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName+"开始造原子弹……");
//做造原子弹需要做20秒
try {
Thread.sleep(3_000);
System.out.println("3秒后中断正在await的主线程,告诉他不要等了");
mainThread.interrupt();
Thread.sleep(17_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName+"原子弹制造完毕!");
}
}.start();
//主线程去等待子线程做完某事在往下执行
System.out.println("主线程:开始等待子线程……");
try {
cdl.await();
} catch (InterruptedException e) {
System.out.println("主线程:被通知到不要等了,原子弹不是3秒钟就能造出来的!");
}
System.out.println("主线程:执行完毕!");
}
}
CyclicBarrier: 1
package day03.part3;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* 栅栏:本人比喻为:检测站
* @author xzq
*/
public class CyclicBarrierTest01 {
public static void main(String[] args) throws InterruptedException {
//公司要在北京开董事会,公司总共3个董事
final CyclicBarrier barrier=new CyclicBarrier(3);
/*final CyclicBarrier barrier=new CyclicBarrier(3,new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"所有人已到达北京,召开董事会!");
}
});*/
//创建3个董事线程
for(int i=1;i<=3;i++){
new Thread("董事"+i+":"){
@Override
public void run() {
try {
String threadName = Thread.currentThread().getName();
System.out.println(threadName+"出发前往北京……");
//董事1到达北京需要1秒
if("董事1:".equals(threadName)){
Thread.sleep(1000);
}else if("董事2:".equals(threadName)){//董事2到达北京需要3秒
Thread.sleep(3000);
}else{//董事3到达北京需要4秒
Thread.sleep(4000);
}
System.out.println(threadName+"已到达北京!");
//getNumberWaiting方法,当调用await之后这个数字就会减1
int waittingNum =barrier.getNumberWaiting();
System.out.println(threadName+"当前有"+(waittingNum+1)+"个董事到达北京。");
barrier.await();
//每一个董事都知道自己到达后自己还需不需要等待
System.out.println(threadName+"总共需要"+barrier.getParties()+"人才能开董事会!");
if(waittingNum==0){
System.out.println(threadName+"所有人已经到达北京,召开董事会!");
}
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}.start();
}
}
}
CyclicBarrier: 2、对中断的处理
package day03.part3;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* 栅栏:本人比喻为:检测站
* 对中断的处理
* @author xzq
*/
public class CyclicBarrierTest02 {
public static void main(String[] args) throws InterruptedException {
//公司要在北京开董事会,公司总共3个董事
final CyclicBarrier barrier=new CyclicBarrier(3);
Thread t1 = new Thread("董事1:"){
@Override
public void run() {
String threadName = Thread.currentThread().getName();
try {
System.out.println(threadName+"出发前往北京……");
//董事1到达北京需要1秒
Thread.sleep(1000);
System.out.println(threadName+"已到达北京!");
//getNumberWaiting方法,当调用await之后这个数字就会减1
int waittingNum =barrier.getNumberWaiting();
barrier.await();
if(waittingNum==0){
System.out.println(threadName+"所有人已经到达北京,召开董事会!");
}
} catch (InterruptedException e) {
System.out.println(threadName+"我被杀掉了!");
} catch (BrokenBarrierException e) {
System.out.println(threadName+"有董事被杀掉了!");
}
}
};
Thread t2 = new Thread("董事2:"){
@Override
public void run() {
String threadName = Thread.currentThread().getName();
try {
System.out.println(threadName+"出发前往北京……");
//董事2到达北京需要2秒
Thread.sleep(2000);
System.out.println(threadName+"已到达北京!");
//getNumberWaiting方法,当调用await之后这个数字就会减1
int waittingNum =barrier.getNumberWaiting();
System.out.println(threadName+"此时isBroken的状态为:"+barrier.isBroken());
barrier.await();
if(waittingNum==0){
System.out.println(threadName+"所有人已经到达北京,召开董事会!");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
System.out.println(threadName+"有董事被杀掉了!");
}
}
};
Thread t3 = new Thread("董事3:"){
@Override
public void run() {
String threadName = Thread.currentThread().getName();
try {
System.out.println(threadName+"出发前往北京……");
//董事3到达北京需要4秒
Thread.sleep(4000);
System.out.println(threadName+"已到达北京!");
//getNumberWaiting方法,当调用await之后这个数字就会减1
int waittingNum =barrier.getNumberWaiting();
System.out.println(threadName+"此时isBroken的状态为:"+barrier.isBroken());
barrier.await();
if(waittingNum==0){
System.out.println(threadName+"所有人已经到达北京,召开董事会!");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
System.out.println(threadName+"有董事被杀掉了!");
}
}
};
t1.start();
t2.start();
t3.start();
//主线程在2.5秒后中断董事1
Thread.sleep(2500);
t1.interrupt();
System.out.println("主线程执行完毕!");
}
}
CyclicBarrier: 3、使用reset方法
package day03.part3;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* 栅栏:本人比喻为:检测站
* 使用reset方法
* @author xzq
*/
public class CyclicBarrierTest03 {
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
//公司要在北京开董事会,公司总共3个董事
final CyclicBarrier barrier=new CyclicBarrier(3);
Thread t1 = new Thread("董事1:"){
@Override
public void run() {
String threadName = Thread.currentThread().getName();
try {
System.out.println(threadName+"出发前往北京……");
//董事1到达北京需要1秒
Thread.sleep(1000);
System.out.println(threadName+"已到达北京!");
//getNumberWaiting方法,当调用await之后这个数字就会减1
int waittingNum =barrier.getNumberWaiting();
barrier.await();
if(waittingNum==0){
System.out.println(threadName+"所有人已经到达北京,召开董事会!");
}
} catch (InterruptedException e) {
} catch (BrokenBarrierException e) {
}
}
};
Thread t2 = new Thread("董事2:"){
@Override
public void run() {
String threadName = Thread.currentThread().getName();
try {
System.out.println(threadName+"出发前往北京……");
//董事2到达北京需要2秒
Thread.sleep(2000);
System.out.println(threadName+"已到达北京!");
//getNumberWaiting方法,当调用await之后这个数字就会减1
int waittingNum =barrier.getNumberWaiting();
barrier.await();
if(waittingNum==0){
System.out.println(threadName+"所有人已经到达北京,召开董事会!");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
}
}
};
Thread t3 = new Thread("董事3:"){
@Override
public void run() {
String threadName = Thread.currentThread().getName();
try {
System.out.println(threadName+"出发前往北京……");
//董事3到达北京需要4秒
Thread.sleep(4000);
System.out.println(threadName+"已到达北京!");
//getNumberWaiting方法,当调用await之后这个数字就会减1
int waittingNum =barrier.getNumberWaiting();
barrier.await();
if(waittingNum==0){
System.out.println(threadName+"所有人已经到达北京,召开董事会!");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
}
}
};
t1.start();
t2.start();
t3.start();
//主线程在1.5秒后调用reset方法,表示自己也要参加董事会
Thread.sleep(1500);
System.out.println("主线程:已经有"+barrier.getNumberWaiting()+"个董事到达北京!");
barrier.reset();//将倒计时重置
//主线程花了2秒到达北京
Thread.sleep(2000);
System.out.println("主线程:已经到达北京!");
barrier.await();
System.out.println("主线程执行完毕!");
}
}