java并发编程之CountDownLatch和CyclicBarrier的使用

CountDownLatch的使用

类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的使用

类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类可以使同类线程互相等待达到同步的效果,使用这两个类可以更加完善地实现线程对象之间的同步性,对线程对象执行的轨迹控制更加方便。

你可能感兴趣的:(Java并发编程)