栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

并发编程--CountdownLatch && CyclicBarrier

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

并发编程--CountdownLatch && CyclicBarrier

Semaphore,CountdownLatch,CyclicBarrier都是java提供的同步辅助类。
上一篇对Semaphore有了一定的了解,本篇则针对CountdownLatch以及CyclicBarrier进行一定的总结。

一、CountdownLatch 1)CountdownLatch是什么?

CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)
能够使一个线程等待其他线程完成各自的工作之后再执行。例如zookeeper分布式锁的实现。而Semaphore则主要强调的是资源有限。

2)CountdownLatch使用场景

比如老公陪同媳妇去医院,媳妇等候医生看病,老公则针对单子去拿药,两者都完工,则一起回家。再比如老板等10个员工开会,只有10个员工都到齐了,会议才能开始等等场景。

3)应用demo

举例说明老板等待员工开会的场景:

public static void main(String[] args) {
		//老板需要等待15个员工会议室开会
		final CountDownLatch latch = new CountDownLatch(15);
		for (int i = 0; i < 15; i++) {
			Random random = new Random();
			final int timer = random.nextInt(1000);
			new Thread(() -> {
				try {
					System.out.println("子线程" + Thread.currentThread().getName() + "正在赶路");
					//模仿每个员工走自己线程需要的时间
					Thread.sleep(1000 + timer);
					//调用latch的countDown方法使计数器-1;一共15个
					latch.countDown();
					System.out.println("子线程" + Thread.currentThread().getName() + "到会议室了");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}).start();
		}

		try {
			System.out.println("领导等待员工会议室开会...");
			//主线程阻塞等待计数器归零
			latch.await();
			System.out.println("员工都来了,会议开始");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

执行结果:

子线程Thread-1正在赶路
子线程Thread-3正在赶路
子线程Thread-0正在赶路
子线程Thread-2正在赶路
子线程Thread-4正在赶路
子线程Thread-5正在赶路
子线程Thread-6正在赶路
子线程Thread-7正在赶路
子线程Thread-8正在赶路
子线程Thread-9正在赶路
子线程Thread-10正在赶路
子线程Thread-11正在赶路
子线程Thread-12正在赶路
子线程Thread-13正在赶路
领导等待员工会议室开会…
子线程Thread-14正在赶路
子线程Thread-5到会议室了
子线程Thread-1到会议室了
子线程Thread-12到会议室了
子线程Thread-13到会议室了
子线程Thread-4到会议室了
子线程Thread-6到会议室了
子线程Thread-2到会议室了
子线程Thread-0到会议室了
子线程Thread-3到会议室了
子线程Thread-10到会议室了
子线程Thread-14到会议室了
子线程Thread-8到会议室了
子线程Thread-9到会议室了
子线程Thread-7到会议室了
子线程Thread-11到会议室了
员工都来了,会议开始

4)源码分析

核心关注方法只有两个,latch.countDown();和latch.await();
countDown() 方法每次调用都会将 state 减 1,直到state 的值为 0;而 await 是一个阻塞方法,当 state 减 为 0 的时候,await 方法才会返回。await 可以被多个线程调用,大家在这个时候脑子里要有个图:所有调用了await 方法的线程阻塞在 AQS 的阻塞队列中,等待条件满(state == 0),将线程从队列中一个个唤醒过来。

public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

在 CountDownLatch 内部写了一个 Sync 并且继承了 AQS 这个抽象类重写了 AQS中的共享锁方法。这段代码主要是判定当前线程是否获取到了共享锁

public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        //state 如果不等于 0,说明当前线程需要加入到共享锁队列中
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }
//在共享可中断模式下获取。
private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        //创建一个共享模式的节点添加到队列中
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    //尝试获取锁
                    int r = tryAcquireShared(arg);
                    //r>=0 表示获取到了执行权限,这个时候因为 state!=0,所以不会执行这段代码
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                //阻塞线程
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
二、CyclicBarrier 1)CyclicBarrier是什么?

栅栏屏障,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。
简单理解就是:多个线程之间互相等待,满足条件在同一时间进行。

2)CyclicBarrier使用场景

可以用于多线程计算数据,最后合并计算结果的场景。
又比如旅行团旅行,需要大家都到齐,证件都办理好,才能出发。

3)应用demo

旅行团旅行,需要大家都到齐,证件都办理好,上旅行车才能出发。

public class CyclicBarrierTest1 extends Thread{
	private final CyclicBarrier barrier;
	//随机值处理
	private final Random random = new Random();
	public CyclicBarrierTest1(String name,CyclicBarrier barrier) {
		super(name);
		this.barrier = barrier;
	}

	
	@Override
	public void run() {
		try {
			Thread.sleep(random.nextInt(2000));
			System.out.println(Thread.currentThread().getName() + " - 已经到达旅行团");
			barrier.await();
			Thread.sleep(random.nextInt(2000));
			System.out.println(Thread.currentThread().getName() + " - 证件已经办理好");
			barrier.await();
			Thread.sleep(random.nextInt(2000));
			System.out.println(Thread.currentThread().getName() + " - 已经上旅行车");
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			e.printStackTrace();
		}
		super.run();
	}

	public static void main(String[] args) {
		//旅行团5个游客
		CyclicBarrier cyclicBarrier=new CyclicBarrier(5);
		for (int i=0;i<5;i++){
			new CyclicBarrierTest1("游客-" + (i + 1), cyclicBarrier).start();
		}
	}
}

游客-5 - 已经到达旅行团
游客-3 - 已经到达旅行团
游客-2 - 已经到达旅行团
游客-1 - 已经到达旅行团
游客-4 - 已经到达旅行团
游客-2 - 证件已经办理好
游客-4 - 证件已经办理好
游客-1 - 证件已经办理好
游客-3 - 证件已经办理好
游客-5 - 证件已经办理好
游客-1 - 已经上旅行车
游客-2 - 已经上旅行车
游客-3 - 已经上旅行车
游客-5 - 已经上旅行车
游客-4 - 已经上旅行车

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/306410.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号