线程间控制之CountDownLatch和CyclicBarrier使用介绍

一、CountDownLatch介绍

        CountDownLatch类(采用减法计数);是一个线程同步辅助工具类和CyclicBarrier类(采用加法计数)功能类似,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。

二、CountDownLatch俩种应用场景:

        场景一:所有线程在等待开始信号startSignal.await(),主流程发出开始信号通知,既执行startSignal.countDown()方法后,所有线程才开始执行;每个线程执行完发出做完信号,既执行doneSignal.countDown()方法;当所有线程都执行完毕后,主流程才能继续往下执行。   

package ThreadStudy;

import java.util.concurrent.CountDownLatch;

public class Driver1 {
	
	public static void main(String[] args) throws InterruptedException {
		int N = 5;
		CountDownLatch startSignal = new CountDownLatch(1);
		CountDownLatch doneSignal = new CountDownLatch(N);
		for (int i = 0; i < N; i++) {
			new Thread(new Work1(startSignal, doneSignal)).start();
		}
		//此时所有线程处于等待状态
		System.out.println("doSomethingElse()");
		//让所有线程执行
		startSignal.countDown();
		//等待所有线程执行完毕
		doneSignal.await();
		System.out.println("doSomethingElse()");
		
	}
}

class Work1 implements Runnable {
	
	private final CountDownLatch startSignal;
	private final CountDownLatch doneSignal;
	
	public Work1(CountDownLatch startSignal,CountDownLatch doneSignal) {
		this.startSignal=startSignal;
		this.doneSignal= doneSignal;
	}
	
	@Override
	public void run() {
		try {
			startSignal.await();
			doWork();
			doneSignal.countDown();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	void doWork() {
		System.out.println("doWork()");
	}
}

        场景二:把一个大问题分成N个部分,每一个部分对应一个线程放到线程池中执行,当每一个线程执行完成完毕后发出做完信号,既调用doneSignal.countDown()方法;当所有线程都执行完毕后,主流程才能继续往下执行。

package ThreadStudy;

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

public class Driver2 {
	public static void main(String[] args) throws Exception {
		int N = 5;
		CountDownLatch doneSignal = new CountDownLatch(N);
		//定义线程池
		ExecutorService exec = Executors.newSingleThreadExecutor();
		for (int i = 0; i < N; i++) {
			exec.execute(new Work2(doneSignal, i));
		}
		//等待所有线程执行完成
		doneSignal.await();
		System.out.println("doSomethingElse()");
		//关闭线程池
		exec.shutdown();
	}
}

class Work2 implements Runnable {
	private CountDownLatch doneSignal;
	private int i;

	public Work2(CountDownLatch doneSignal, int i) {
		this.doneSignal = doneSignal;
		this.i = i;
	}

	@Override
	public void run() {
		doWork(i);
		doneSignal.countDown();
	}

	void doWork(int i) {
		System.out.println("doWork():" + i);
	}
}

三、CountDownLatch与CyclicBarrier对比

CountDownLatchCyclicBarrier
相同点都是同步辅助工具类
不同点减法计数,一次性使用加法计数,可循环使用
构造方法

CountDownLatch(int count)

CyclicBarrier(int parties)
CyclicBarrier(int parties, Runnable barrierAction)
普通方法await()await()
await(long timeout, TimeUnit unit)await(long timeout, TimeUnit unit)
countDown()getNumberWaiting()
getCount()getParties()
toString()isBroken()
reset()

四、CountDownLatch类中方法使用示例

package ThreadStudy;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class Csdn {
	public static void main(String[] args) throws Exception {
		int countLatch = 3;
		// 创建指定个数的门闩
		CountDownLatch countDownLatch = new CountDownLatch(countLatch);
		System.out.println("toString方法0:" + countDownLatch.toString());
		for (int i = 0; i < countLatch; i++) {
			new Thread(new Runnable() {

				@Override
				public void run() {
					try {
						// 门闩数减一
						Thread.sleep(3000);
						countDownLatch.countDown();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

				}
			}).start();
		}
		// 获取门闩数量
		long n = countDownLatch.getCount();
		System.out.println("门闩数量:" + n);
		// 指定等待的超时时间
		countDownLatch.await(1, TimeUnit.SECONDS);
		System.out.println("过了超时时间程序继续往下执行");
		// 当前线程等待,直到门闩数是0,程序才往下执行
		countDownLatch.await();
		System.out.println("toString方法1:" + countDownLatch.toString());

	}
}

五、CyclicBarrier类中方法使用示例

package ThreadStudy;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;

public class CyclicBarrierTest {
	public static void main(String[] args) {

		// 构造方法一:创建一个线程为3的循环障碍点,3个线程都到达障碍点后,才往下走!
		 CyclicBarrier cb1 = new CyclicBarrier(3);

		// 构造方法二:创建一个新的CyclicBarrier,当最后一个线程通过障碍点后会触发此处的线程执行
		CyclicBarrier cb = new CyclicBarrier(3, new Runnable() {

			@Override
			public void run() {
				System.out.println("==通过障碍点后触发执行的线程==");
			}
		});
		// 返回当前在屏障处等待的人数。此方法主要用于调试和断言
		int a = cb.getNumberWaiting();
		System.out.println("返回当前在屏障处等待的人数" + a);

		// 返回跨越该障碍所需的人数
		int b = cb.getParties();
		System.out.println("返回跨越该障碍所需的人数:" + b);

		// 查询此屏障是否处于中断状态:
		boolean bo = cb.isBroken();
		System.out.println("查询此屏障是否处于中断状态:" + bo);

		for (int i = 0; i < 4; i++) {

			new Thread(new Runnable() {

				@Override
				public void run() {

					System.out.println("线程:" + Thread.currentThread().getName() + "进入障碍点等待");
					try {
						// 等待,直到所有各方都调用了这个屏障上的await。
						int d = cb.await();
						System.out.println("d:" + d);

						// 等待,直到所有各方都调用了此屏障上的await,或指定的等待时间过去
						int c = cb.await(1, TimeUnit.SECONDS);
						System.out.println("c:" + c);
					} catch (Exception e) {
						e.printStackTrace();
					}
					System.out.println("通过障碍点");

				}
			}).start();
		}
		// 复位操作,此时在障碍点等待的线程会抛出BrokenBarrierException异常
		cb.reset();
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值