Java多线程——java.util.concurrent库中的CyclicBarrier和CountDownLatch工具

在Java的并发库中,有两个并不是经常使用但却非常好用的线程同步工具,分别为CyclicBarrier和CountDownLatch。下面分别对这两个工具进行介绍:


CyclicBarrier

CyclicBarrier允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。


CyclicBarrier的使用方法:通过CyclicBarrier的await()来阻塞线程,实现线程屏障。当某一线程运行到CyclicBarrier的await()方法时,该线程将会被阻塞,直到指定个数的线程调用了await()方法,屏障才会放行。放行所需要的线程个数取决于创建CyclicBarrier对象(调用构造方法)时指定的参数。


CyclicBarrier的主要方法如下:

/*构造方法。当线程调用await()方法后将开始等待,当指定个数的线程调用了await()方法后,
所有调用了await()的线程继续运行。*/
CyclicBarrier(int parties):

//当await的数量到达了设定的数量后,首先执行该Runnable对象。
CyclicBarrier(int parties,Runnable barrierAction):

//通知barrier已完成线程
void await():

//查看当前等待线程的个数
int getNumberWaiting();


具体实例:下面的代码实现了开启三个线程,每个线程都有三个检查点,每当一个程序到达一个检查点,必须等待其他两个线程都到达了这一检查点方能继续运行。


package com.fhp.testutils;

import java.util.Random;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestCyclicBarrier {
	public static void main(String[] args) {
		ExecutorService service = Executors.newCachedThreadPool();
		final CBBusiness business = new CBBusiness();
		for(int i = 0; i < 3; i++) {
			service.execute(new Runnable() {
				
				@Override
				public void run() {
					business.execute();
				}
			});
		}
		
		service.shutdown();
	}
}

class CBBusiness {
	private final CyclicBarrier checkPoint = new CyclicBarrier(3);
	
	public void execute() {
		try {
			Random rand = new Random();
			Thread.sleep(rand.nextInt(5000));
			System.out.println("Checkpoint 1: " + checkPoint.getNumberWaiting());
			checkPoint.await();
			
			Thread.sleep(rand.nextInt(5000));
			System.out.println("Checkpoint 2: " + checkPoint.getNumberWaiting());
			checkPoint.await();
			
			Thread.sleep(rand.nextInt(5000));
			System.out.println("Checkpoint 3: " + checkPoint.getNumberWaiting());
			checkPoint.await();
		} catch(Exception e) {
			e.printStackTrace();
		}
		
	}
}

运行结果:

Checkpoint 1: 0
Checkpoint 1: 1
Checkpoint 1: 2
Checkpoint 2: 0
Checkpoint 2: 1
Checkpoint 2: 2
Checkpoint 3: 0
Checkpoint 3: 1
Checkpoint 3: 2


应用场景:在某种需求中,比如一个大型的任务,常常需要分配很多子任务去执行,只有当所有子任务都执行完成时候,才能执行主任务,这时候,就可以选择CyclicBarrier了。


CountDownLatch

先引入一下官方的定义:CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。


实际上,CountDownLatch类是一个同步计数器,构造时传入int参数,该参数就是计数器的初始值,每调用一次countDown()方法,计数器减1,计数器大于0 时,await()方法会阻塞程序继续执行.利用这种特性,可以让主线程等待子线程的结束。


CountDownLatch的主要方法:

//构造方法,指定计数器的初始值。
CountDownLatch(int count);

//令线程等待,直至计数器归零为止。
void await();
    
//令计数器减1,归零后等待线程将继续执行。
void countDown();

//查看当前计数器的值
long getCount();


具体实例:模拟运动员进行田径跑步比赛的场景。每个运动员需要先在起点就位,待所有运动员就位后,裁判打响发令枪,宣布比赛开始,待所有运动员到达终点后,裁判宣布比赛结束。


package com.fhp.testutils;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestCountDownLatch {
	public static void main(String[] args) {
		final CDLBusniness business = new CDLBusniness(5);
		ExecutorService service = Executors.newCachedThreadPool();
		service.execute(new Runnable() {
			
			@Override
			public void run() {
				try {
					business.referee();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
		for(int i = 1; i <= 5; i++) {
			final int current = i;
			final Random r = new Random();
			service.execute(new Runnable() {
				
				@Override
				public void run() {
					try {
						Thread.sleep(r.nextInt(1500));
						business.athlete(current);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
		}
		service.shutdown();
	}
}

class CDLBusniness {
	private final CountDownLatch athlete;
	
	private final CountDownLatch start = new CountDownLatch(1);
	
	private final CountDownLatch goal;
	
	public CDLBusniness(int numOfAthlete) {
		this.athlete = new CountDownLatch(numOfAthlete);
		this.goal = new CountDownLatch(numOfAthlete);
	}
	
       //运动员的动作
	public void athlete(int id) throws InterruptedException {
		athlete.countDown();
		 System.out.println("Athlete " + id + " has been in place.");
		 start.await();
		 System.out.println("Athlete " + id + " is running.");
		Random r = new Random();
		 Thread.sleep(1000 + r.nextInt(3000));
		 System.out.println("Athlete " + id + " has reached the goal!");
		 goal.countDown();
	}
	
       //裁判的动作
	public void referee() throws InterruptedException {
		 System.out.println("Referee has been in place.");
		athlete.await();
		Random r = new Random();
		Thread.sleep(r.nextInt(2000));
		start.countDown();
		System.out.println("Referee: Match start!");
		goal.await();
		System.out.println("Referee: Match end!");
	}
}


  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值