类CountDownLatch所提供的功能是判断count计数不为0时则当前线程呈wait状态,也就是在屏障处等待,
2.1.1初步使用
private CountDownLatch down = new CountDownLatch(1);//初始化一个给定计数值的CountDownLatch
down.await();//除非线程被中断,否则导致当前线程等待直到锁存器倒计数到零
down.countDown();//减少计数的值,直到计数值为0释放所有等待的线程。
2.1.2裁判在等全部的运动员到来
package cn.yu.countdownlatch;
import java.util.concurrent.CountDownLatch;
public class MyThread extends Thread{
private CountDownLatch comingTag;//裁判等待所有运动员到来
private CountDownLatch waitTag; //等待裁判说准备开始
private CountDownLatch waitRunTag;//等待起跑
private CountDownLatch beginTag;//起跑
private CountDownLatch endTag;//所有运动员到达终点
public MyThread( CountDownLatch comingTag, CountDownLatch waitTag, CountDownLatch waitRunTag, CountDownLatch beginTag,
CountDownLatch endTag) {
super();
this.comingTag = comingTag;
this.waitTag = waitTag;
this.waitRunTag =waitRunTag;
this.beginTag = beginTag;
this.endTag = endTag;
}
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"运动员使用不同交通工具不同速度到达,正向这边走!");
Thread.sleep((int)Math.random()*10000);
comingTag.countDown();
System.out.println(Thread.currentThread().getName()+"运动员已经到达,等裁判说开始");
waitTag.await();
System.out.println(Thread.currentThread().getName()+"各就各位,准备起跑");
Thread.sleep((int)Math.random()*10000);
waitRunTag.countDown();
beginTag.await();
System.out.println(Thread.currentThread().getName()+"运动员开始跑");
Thread.sleep((int)Math.random()*10000);
endTag.countDown();
System.out.println(Thread.currentThread().getName()+"运动员到达终点!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package cn.yu.countdownlatch;
import java.util.concurrent.CountDownLatch;
public class Run {
public static void main(String[] args) {
try {
CountDownLatch comingTag = new CountDownLatch(10);
CountDownLatch waitTag = new CountDownLatch(1);
CountDownLatch waitRunTag = new CountDownLatch(10);
CountDownLatch beginTag = new CountDownLatch(1);
CountDownLatch endTag = new CountDownLatch(10);
MyThread[] threadArray = new MyThread[10];
for(int i =0;i<threadArray.length;i++) {
threadArray[i] = new MyThread(comingTag,waitTag,waitRunTag,beginTag,endTag);
threadArray[i].start();
}
System.out.println("等待运动员们到达!-------");
comingTag.await();
System.out.println("运动员全部到达,裁判巡视!-------------");
Thread.sleep(5000);
waitTag.countDown();
System.out.println("裁判喊各就各位!");
waitRunTag.await();
Thread.sleep(2000);
System.out.println("发令枪响起!");
beginTag.countDown();
endTag.await();
Thread.sleep(5000);
System.out.println("所有运动员到达");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:
Thread-0运动员使用不同交通工具不同速度到达,正向这边走!
Thread-1运动员使用不同交通工具不同速度到达,正向这边走!
Thread-2运动员使用不同交通工具不同速度到达,正向这边走!
Thread-3运动员使用不同交通工具不同速度到达,正向这边走!
Thread-5运动员使用不同交通工具不同速度到达,正向这边走!
Thread-3运动员已经到达,等裁判说开始
Thread-1运动员已经到达,等裁判说开始
Thread-5运动员已经到达,等裁判说开始
Thread-4运动员使用不同交通工具不同速度到达,正向这边走!
Thread-4运动员已经到达,等裁判说开始
Thread-0运动员已经到达,等裁判说开始
Thread-2运动员已经到达,等裁判说开始
Thread-6运动员使用不同交通工具不同速度到达,正向这边走!
Thread-6运动员已经到达,等裁判说开始
Thread-7运动员使用不同交通工具不同速度到达,正向这边走!
Thread-7运动员已经到达,等裁判说开始
等待运动员们到达!-------
Thread-8运动员使用不同交通工具不同速度到达,正向这边走!
Thread-9运动员使用不同交通工具不同速度到达,正向这边走!
Thread-9运动员已经到达,等裁判说开始
运动员全部到达,裁判巡视!-------------
Thread-8运动员已经到达,等裁判说开始
裁判喊各就各位!
Thread-4各就各位,准备起跑
Thread-0各就各位,准备起跑
Thread-6各就各位,准备起跑
Thread-9各就各位,准备起跑
Thread-1各就各位,准备起跑
Thread-8各就各位,准备起跑
Thread-7各就各位,准备起跑
Thread-3各就各位,准备起跑
Thread-2各就各位,准备起跑
Thread-5各就各位,准备起跑
发令枪响起!
Thread-4运动员开始跑
Thread-6运动员开始跑
Thread-6运动员到达终点!
Thread-3运动员开始跑
Thread-3运动员到达终点!
Thread-5运动员开始跑
Thread-5运动员到达终点!
Thread-0运动员开始跑
Thread-2运动员开始跑
Thread-2运动员到达终点!
Thread-7运动员开始跑
Thread-8运动员开始跑
Thread-1运动员开始跑
Thread-1运动员到达终点!
Thread-9运动员开始跑
Thread-4运动员到达终点!
Thread-9运动员到达终点!
Thread-8运动员到达终点!
Thread-7运动员到达终点!
Thread-0运动员到达终点!
所有运动员到达
2.1.3 方法await(long timeout,TimeUnit unit)
方法await(long timeout,TimeUnit unit)的作用使线程在指定的最大时间单位内进入waiting状态,如果超过这个时间则自动唤醒,程序继续向下运行。参数timeout是等待的时间,而unit参数是时间的单位。
2.1.4 方法 getCount()的使用
获取当前计数的值
类CyclicBarrier不仅有CountDownLatch锁具有的功能,还可以实现屏障等待的功能,也就是阶段性同步,它在使用上的意义在于可以循环地实现线程要一起做任务的目标,而不是像类CountDownLatch一样,仅仅支持一次线程与同步点阻塞的特性。
类CyclicBarrier和Semaphore及CountDownLatch一样,也是一个同步辅助类。它允许一组线程互相等待,直到到达某个公共屏障点,这些线程必须实时地互相等待。这种情况下就可以使用CyclicBarrier类来方便地实现这样的功能。CyclicBarrier类的公共屏障点可以重用。
CountDownLatch与CyclicBarrier的区别
1.CountDownLatch作用:一个线程或者多个线程,等待另外一个线程或者多个线程完成某个事情之后才能继续执行。
2.CyclicBarrier 作用:多个线程之间互相等待,任何一个线程完成之前,所有的线程都必须等待,所以对于CyclicBarrier来说,重点是“多个线程之间”任何一个线程没有完成任务,则所有的线程都必须等待。
2.2.1 初步使用
CountDownLatch最大的弊端是CountDownLatch类的计数不可以重置,想要再次获得同步的功能只有通过添加代码,增加代码的复杂度才可以换取想要实现的功能。
创建一个新的CyclicBarrier,当给定数量的线程正在等待它时将跳闸,
并且当屏障被触发时执行给定的屏障动作,由进入屏障的最后一个线程执行。
CyclicBarrier cbRef = new CyclicBarrier(5,new Runnable(){
public void run(){
System.out.println("全都到了");
}
});
CyclicBarrier cyclicbarrier = new CyclicBarrier(int parties,Runnable barrierAction);
设置最大个数为parties同行者,当parties个线程都执行了CyclicBarrier对象的await()
方法后程序才可以继续向下执行。
2.2.2 验证屏障重置性及getNumberWaiting()方法的使用
类CyclicBarrier具有重置性,每当等待线程数量到达parties数量时,所有等待的线程开始执行,并且parties值置为0。
方法getNumberWaiting() 返回此刻等待的线程数
2.2.3 方法isBroken()的使用
方法isBroken()查询此屏障是否处于损坏状态。
2.2.4方法await(long timeout,TimeUnit unit)超时出现异常的测试
方法await(long timeout,TimeUnit unit)的功能是如果在指定的时间内达到parties的数量,则程序继续向下运行,否则如果出现超时,则抛出TimeoutException异常。
2.2.5 方法getNumberWaiting()和getParties()的使用
方法getNumberWaiting()的作用是有几个线程已经到达屏障点。
方法getParties()的作用是取得parties个数。
2.2.6 方法reset()
方法reset()的作用是重置屏障
本章总结:
使用CountDownLatch类可以实现两种角色的线程等待对方的效果,而CyclicBarrier类可以使同类线程互相等待达到同步的效果,使用这两个类可以更加完善地实现线程对象之间的同步性,对线程对象执行的轨迹控制更加方便。