并发栅栏CyclicBarrier---简单问

背景:前几天在网上看到关于Java并发包java.concurrent中一个连环炮的面试题,整理下以备不时之需。

CyclicBarrier简介:

栅栏类似于闭锁,它能够阻塞一组线程直到某个事件发生;它与闭锁(CountDownLatch)的区分关键在于,闭锁是所有线程等待一个外部事件的发生;而栅栏则是所有线程相互等待,直到所有线程都到达某一点时才打开栅栏,然后线程可以继续执行。

问题:

如果想实现所有的线程一起等待某个事件的发生,当某个事件发生时,所有线程一起开始往下执行的话,有什么好的办法吗?

回答:

可以使用栅栏,Java并发包中的CyclicBarrier。

又问:

你知道CyclicBarrier的实现原理吗?

回答:

CyclicBarrier.await方法调用CyclicBarrier.dowait方法,每次调用await方法都会使计数器-1,当减少到0时就会唤醒所有的线程。(计数器count就是线程总数,CyclicBarrier cyclicBarrier = new CyclicBarrier(100);)最核心的部分就是 int index = --count; 和 nextGeneration();方法。

 public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
 public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
 private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Generation g = generation; if (g.broken)
throw new BrokenBarrierException(); if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
} int index = --count; // 最核心的部分就是此处1
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration(); // 最核心的部分就是此处2
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
} // loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
} if (g.broken)
throw new BrokenBarrierException(); if (g != generation)
return index; if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
 private void nextGeneration() {
// signal completion of last generation
trip.signalAll();
// set up next generation
count = parties;
generation = new Generation();
}

又问:

除此之外,您还知道其它的实现方式吗?

回答:

方案1:读写锁,刚开始主线程获取写锁,然后所有子线程获取读锁,然后等事件发生时主线程释放写锁;

方案2:CountDownLatch闭锁,CountDownLatch初始值设为1,所有子线程调用await方法等待,等事件发生时调用countDown方法计数减为0;

方案3:Semaphore,Semaphore初始值设为N,刚开始主线程先调用acquire(N)申请N个信号量,其他线程调用acquire()阻塞等待,等事件发生时同时主线程释放N个信号量。

CountDownLatch闭锁实现模拟如下:

 import java.util.concurrent.CountDownLatch;

 public class CountDownLatchDemo {

 /**
* 模拟老爸去饭店
*/
public static void fatherToRes()
{
System.out.println("老爸步行去饭店需要3小时。");
} /**
* 模拟老妈去饭店
*/
public static void motherToRes()
{
System.out.println("老妈挤公交去饭店需要2小时。");
} /**
* 模拟我去饭店
*/
public static void meToRes()
{
System.out.println("我乘地铁去饭店需要1小时。");
} /**
* 模拟一家人到齐了
*/
public static void togetherToEat()
{
System.out.println("一家人到齐了,开始吃饭");
} private static CountDownLatch latch = new CountDownLatch(3); public static void main(String[] args) throws InterruptedException
{ new Thread()
{
public void run()
{
fatherToRes();
latch.countDown();
};
}.start();
new Thread()
{
public void run()
{
motherToRes();
latch.countDown();
};
}.start();
new Thread()
{
public void run()
{
meToRes();
latch.countDown();
};
}.start(); latch.await();
togetherToEat();
}
}

又问:

您觉得这些方式里哪个方式更好呢?

回答:

CountDownLatch闭锁是等待一组线程执行完毕后才能继续执行;

CyclicBarrier栅栏是能让一组线程达到一个同步点时被阻塞,直到最后一个线程达到,阻塞才会消失,其是可以循环使用的;

Semaphore信号量是只允许一定数量的线程同时执行,一般用来限制访问资源的线程数量。

又问:

如果你这个时候依然可以说出来你自己更好的实现方式,那么面试官肯定还会揪着这个继续问你。

并发栅栏CyclicBarrier---简单问2的更多相关文章

  1. 并发编程 04——闭锁CountDownLatch 与 栅栏CyclicBarrier

    Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...

  2. Java并发编程原理与实战二十七:循环栅栏:CyclicBarrier

    昨天我们学习了倒计数功能的等待,今天我们学习的是循环栅栏:CyclicBarrier.下面我们就开始吧: 1.CyclicBarrier简介CyclicBarrier,是JDK1.5的java.uti ...

  3. java高并发系列 - 第17天:JUC中的循环栅栏CyclicBarrier常见的6种使用场景及代码示例

    这是java高并发系列第17篇. 本文主要内容: 介绍CyclicBarrier 6个示例介绍CyclicBarrier的使用 对比CyclicBarrier和CountDownLatch Cycli ...

  4. 多线程-栅栏CyclicBarrier

    上一篇总结了闭锁CountDownLatch,这一篇总结一下栅栏CyclicBarrier.它们两者之间的区别主要是,闭锁是等待一个事件发生,比如上一篇的田径比赛,运动员等待裁判哨声一响就可以开始跑, ...

  5. JVM&NIO&HashMap简单问

    JVM&NIO&HashMap简单问 背景:前几天在网上看到关于JVM&NIO&HashMap的一些连环炮的面试题,整理下以备不时之需. 一.JVM Java的虚拟机的 ...

  6. 并发工具CyclicBarrier源码分析及应用

      本文首发于微信公众号[猿灯塔],转载引用请说明出处 今天呢!灯塔君跟大家讲: 并发工具CyclicBarrier源码分析及应用 一.CyclicBarrier简介 1.简介 CyclicBarri ...

  7. 栅栏——CyclicBarrier

    栅栏CyclicBarrier和闭锁CountDownLatch类似,可以说它们都是用来计数,都能阻塞一组线程知道某个事件发生.不同的是闭锁用于等待事件,而栅栏用于等待其他线程. 在前一篇<Co ...

  8. 多线程之倒计时器CountDownLatch和循环栅栏CyclicBarrier

    1.倒计时器CountDownLatch CountDownLatch是一个多线程控制工具类.通常用来控制线程等待,它可以让一个线程一直等待知道计时结束才开始执行 构造函数: public Count ...

  9. Linux并发执行很简单,这么干就对了

    嗯,就像标题说的那么简单而已 &的并发功能 time for i in `grep server /etc/hosts | awk '{print $1}'`; do (ssh $i &quo ...

随机推荐

  1. kubernetes实战篇之helm安装

    系列目录 Helm是kubernetes的应用包管理工具,是CNCF孵化器下的一个项目,主要用来管理 Charts.类似于 Ubuntu 中的 APT 或 CentOS 中的 YUM.它提供了一种简单 ...

  2. hdoj1009 FatMouse' Trade——贪心算法

    贪心思路:按单位猫粮能兑换到的javaBean从大到小将组合进行排序,总是在当前兑换尽可能多的javabeans 问题描述:点击打开链接 hdoj1009 FatMouse's Trade 源代码: ...

  3. 简单的scrapy实例

    前天实验室的学长要求写一个简单的scrapy工程出来,之前也多少看了点scrapy的知识,但始终没有太明白,刚好趁着这个机会,加深一下对scrapy工作流程的理解.由于临近期末,很多作业要做(其实.. ...

  4. Anemic Model

    In object-oriented programming, and especially in Domain-Driven Design, objects are said to be anemi ...

  5. c++ 逆序对

    c++ 求逆序对 例如数组(3,1,4,5,2)的逆序对有(3,1)(3,2)(4,2)(5,2)共4个 逆序对就是左边的元素比右边的大,那么左边的元素和右边的元素就能产生逆序对 代码跟归并排序差不多 ...

  6. struts2入门Demo

    一.引入必要的jar包,所需jar包如下: 二.配置web.xml.主要目的是拦截请求 <?xml version="1.0" encoding="UTF-8&qu ...

  7. 使用Gitlab-CI 实现NetCore项目Docker化并部署到阿里云K8S

    使用Gitlab-CI 实现NetCore项目Docker化并部署到阿里云K8S 先行条件: 1.了解NetCore项目基础命令,如dotnet publish   等几个常用命令. 2.了解Dock ...

  8. SQL Server 根据日期分组、 根据时间段分组(每三个小时一组)

    所用数据表: 一.根据日期分组 1. 使用convert() 函数方式 --根据年月 ),CreatTime,)日期,COUNT(*) 次数,sum(Money)总数 from Orders ),Cr ...

  9. [译]Vulkan教程(33)多重采样

    [译]Vulkan教程(33)多重采样 Multisampling 多重采样 Introduction 入门 Our program can now load multiple levels of d ...

  10. activiti学习笔记

    activiti入门 activiti官网 pom.xml文件 xml <!-- activiti --> <dependency> <groupId>org.ac ...