1.CountDownLatch和CyclicBarrier的相似处和不同处:
CountDownLatch是通过一个计数器来实现的,当我们在new 一个CountDownLatch对象的时候需要带入该计数器值,该值就表示了线程的数量。每当一个线程完成自己的任务后,计数器的值就会减1。当计数器的值变为0时,就表示所有的线程均已经完成了任务,然后就可以恢复等待的线程继续执行了。
虽然,CountDownlatch与CyclicBarrier有那么点相似,但是他们还是存在一些区别的:
CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待
CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。
CountDownLatch最关键的一个参数就是count。
CountDownLatch的几个核心方法:
await()方法 //countDownLatch的await()方法会使当前线程在锁存器倒计数至零之前,一直等待,除非线程被中断。
countDown()方法 // countDown()方法可以递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
总结起来,就是CountDownLatch有三个核心部分:
p1.是 count 计数器
p2.是 await()方法,使当前线程阻塞,直到count的值为0。
p3.是 countDown()方法,使计数器器的值减一。
应用场景是这样的:
线程A的运行需要同时拥有N个资源,而这N个资源却被n1,n2,n3, ......,nn个线程分别占有者。
所以:A要想运行的话,它就必须等待n1,n2,n3,......,nn这n个线程都把各自占有的资源释放了才行。
其实,它就是一把 共享资源锁。
2.用一段故事说明一下
相当于现在有一个保险柜,这个保险柜上有三把锁,只有把这三把锁都打开才能打开保险柜 。而这三把锁却被分别交给了三个管理员A,B,C手中。所以,如果我们想打开这个保险柜的话,就必须集齐所有的三把锁。
有一天老板来视察工作,想看下保险柜的钱少了,没有,就找来经理。让经理开门,经理说,你等一下,我打三个电话,把人叫齐了才能把门打开。你现在必须先等一下。于是,经理叫开始逐个打电话,他先打给A,"赶快带上钥匙来公司一趟,老板在等着你",1分钟后,A来了,带来了一把钥匙。然后,经理继续给B打电话,"兄弟,赶快来公司一趟,把钥匙带上,老板要检查保险柜"。2分钟后,B来了。最后,经理又给C打了一个电话,"你他娘的,带上钥匙赶快来公司。" 5分钟后,C也来了,就这样。老板在等候了8分钟后终于集齐了三把钥匙,打开了保险柜,看到了自己的小金库。经过漫长而艰辛的等待他欣慰地漏出了笑容。
3.demo案例
需求:
过来一个请求,这个请求传递过来一个集合,要求我们分别算出该集合元素的总和、积、所有偶数值,并存入库中,然后把处理结果返回客户端。
3.1 创建三个负责和、积、偶数值的Runnable
public class AddRunnable implements Runnable {
private CountDownLatch countDown;
private List
dataList; public AddRunnable(CountDownLatch countDown,List
dataList) { super();
this.countDown = countDown;
this.dataList = dataList;
}
@Override
public void run() {
Thread.currentThread().setName("sum线程");
//计算和
Long sum=0l;
for (Integer value : dataList) {
sum=sum+value;
}
//计算出来总和后,把结果存库
System.out.println("计算结果是:"+sum+" 把计算结果存库!");
countDown.countDown();//释放锁
System.out.println(Thread.currentThread().getName()+"释放了一把共享锁");
}
}
乘积:
public class MultiRunnable implements Runnable {
private CountDownLatch countDown;
private List
dataList; public MultiRunnable(CountDownLatch countDown, List
dataList) { super();
this.countDown = countDown;
this.dataList = dataList;
}
@Override
public void run() {
// TODO Auto-generated method stub
Thread.currentThread().setName("muti线程");
//计算和
Long muti=1l;
for (Integer value : dataList) {
muti=muti*value;
System.out.println(muti);
}
//计算出来总和后,把结果存库
System.out.println("乘积结果是:"+muti+" 把乘积结果存库!");
countDown.countDown();//释放锁
System.out.println(Thread.currentThread().getName()+"释放了一把共享锁");
}
}
所有偶数值:
public class OddRunnable implements Runnable {
private CountDownLatch countDown;
private List
dataList; public OddRunnable(CountDownLatch countDown, List
dataList) { super();
this.countDown = countDown;
this.dataList = dataList;
}
@Override
public void run() {
// TODO Auto-generated method stub
// TODO Auto-generated method stub
Thread.currentThread().setName("odd线程");
List
oddList=new ArrayList (); // 计算和
for (Integer value : dataList) {
if(value%2==0) {
oddList.add(value);
}
}
// 计算出来总和后,把结果存库
System.out.println("求偶结果是:" + oddList.size() + " 把求偶结果存库!");
countDown.countDown();// 释放锁
System.out.println(Thread.currentThread().getName() + "释放了一把共享锁");
}
}
测试:
/**
* 需求:
* 过来一个请求,这个请求传递过来一个集合,要求我们分别算出该集合元素的总和、积、所有偶数值,并存入库中,然后把处理结果返回客户端。
* @author chihaojie
*
*/
public class CountDownLatchTest {
private static CountDownLatch countDown;
public static void main(String[] args) {
//只有在其他三个子运算全部完成时,当前线程才能继续
//ExecutorService executorService = Executors.newFixedThreadPool(3);
List
dataList=new ArrayList (); for (int i = 0; i < 10; i++) {
dataList.add(i+1);
}
System.out.println(dataList);
//处理
countDown=new CountDownLatch(3);
//开启三个线程
new Thread(new AddRunnable(countDown, dataList)).start();;
new Thread(new MultiRunnable(countDown, dataList)).start();;
new Thread(new OddRunnable(countDown, dataList)).start();;
//执行
try {
countDown.await();
System.out.println("所有的线程都运算完了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}