CyclicBarrier和CountDownLatch的区别

  • CountDownLatch:一个或者多个线程,等待其他多个线程完成某件事情之后才能执行;
  • CyclicBarrier:多个线程互相等待,直到到达同一个同步点,再继续一起执行

对于CountDownLatch来说,重点是“一个线程(多个线程)等待”,而其他的N个线程在完成“某件事情”之后,可以终止,也可以等待。而对于CyclicBarrier,重点是多个线程,在任意一个线程没有完成,所有的线程都必须互相等待,然后继续一起执行。

CountDownLatch是计数器,线程完成一个记录一个,只不过计数不是递增而是递减,而CyclicBarrier更像是一个阀门,需要所有线程都到达,阀门才能打开,然后继续执行。

CyclicBarrier介绍

  • CyclicBarrier(int parties)
    默认构造方法,参数表示拦截的线程数量。这里的parties也是一个计数器,例如,初始化时parties里的计数是3,于是拥有该CyclicBarrier对象的线程当parties的计数为3时就唤醒,注:这里parties里的计数在运行时当调用CyclicBarrier:await()时,计数就加1,一直加到初始的值

  • CyclicBarrier(int parties, Runnable barrierAction)
    由于线程之前的调度是由CPU决定的,所以默认的构造方法无法设置线程执行优先级,CyclicBarrier提供一个更高级的构造函数CyclicBarrier(int parties, Runnable barrierAction),用于在线程到达同步点时,优先执行线程barrierAction,这样可以更加方便的处理一些负责的业务场景。

使用案例如下:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

class Player implements Runnable {

	private CyclicBarrier cyclicBarrier;
	private int id;
	
	public Player(int id, CyclicBarrier cyclicBarrier) {
	    this.cyclicBarrier = cyclicBarrier;
	    this.id = id;
	}
	
	@Override
	public void run() {
		try {
			System.out.println("玩家" + id + "第一关");
			cyclicBarrier.await();//设置的四个,四个完成后才会执行后面的操作
			System.out.println("玩家" + id + "进入第二关");
			cyclicBarrier.await();
			System.out.println("hahaha");
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			e.printStackTrace();
		}
	}
	
}

public class CyclicBarrierTest {
	public static void main(String[] args) {
		CyclicBarrier cyclicBarrier = new CyclicBarrier(4, new Runnable() {
			
			@Override
			public void run() {
				//阻塞打开后才执行下面的操作
				System.out.println("进入第二关");
			}
		});
		
		for(int i = 0; i < 4; i++) {
			new Thread(new Player(i, cyclicBarrier)).start();
		}
		
	}
}

输出打印:

玩家0第一关
玩家2第一关
玩家1第一关
玩家3第一关
进入第二关
玩家1进入第二关
玩家0进入第二关
玩家3进入第二关
玩家2进入第二关
进入第二关
hahaha
hahaha
hahaha
hahaha

CountDownLatch介绍

对于CountDownLatch,其他线程为游戏玩家,比如英雄联盟,主线程为控制游戏开始的线程。在所有的玩家都准备好之前,主线程是处于等待状态的,也就是游戏不能开始。当所有的玩家准备好之后,下一步的动作实施者为主线程,即开始游戏。

我们使用代码模拟这个过程,我们模拟了三个玩家,在三个玩家都准备好之后,游戏才能开始。代码的输出结果为:
 

正在等待所有玩家准备好
player0 已经准备好了, 所使用的时间为 2.402s
player2 已经准备好了, 所使用的时间为 2.415s
player3 已经准备好了, 所使用的时间为 2.552s
player1 已经准备好了, 所使用的时间为 2.84s
开始游戏

CountDownLatch的代码:

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

public class countdownlatch {
	public static void main(String[] args) throws InterruptedException {
		CountDownLatch latch = new CountDownLatch(4);
		for(int i = 0; i < 4; i++) {
			new Thread(new MyThread(latch), "player" + i).start();
		}
		System.out.println("正在等待所有玩家准备好");
		latch.await();
		System.out.println("开始游戏");
	}
}

class MyThread implements Runnable {

	private CountDownLatch latch;
	
	public MyThread(CountDownLatch latch) {
		this.latch = latch;
	}
	
	@Override
	public void run() {
		try {
            Random rand = new Random();
            int randomNum = rand.nextInt((3000 - 1000) + 1) + 1000;//产生1000到3000之间的随机整数
            Thread.sleep(randomNum);
            System.out.println(Thread.currentThread().getName()+" 已经准备好了, 所使用的时间为 "+((double)randomNum/1000)+"s");
            latch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
	}
	
}

参考博客:

https://blog.csdn.net/liangyihuai/article/details/83106584

https://www.cnblogs.com/twoheads/p/9555867.html

https://blog.csdn.net/qweqwruio/article/details/81359780

 

你可能感兴趣的:(Java基础)