当前位置:网站首页>线程间控制之CountDownLatch和CyclicBarrier使用介绍

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

2022-04-23 14:07:00 pureluckyfish

一、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对比

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

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();
	}
}

版权声明
本文为[pureluckyfish]所创,转载请带上原文链接,感谢
https://blog.csdn.net/sinat_33918956/article/details/122469143