【Java并发编程四】关卡
一、什么是关卡?
关卡类似于闭锁,它们都能阻塞一组线程,直到某些事件发生。
关卡和闭锁关键的不同在于,所有线程必须同时到达关卡点,才能继续处理。闭锁等待的是事件,关卡等待的是其他线程。
二、CyclicBarrier
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。
当线程到达关卡点时,调用await方法,await会被阻塞,直到所有的线程都到达关卡点。如果所有的线程都到达了关卡点,关卡就会被突破,这样所有的线程都被释放,关卡会重置以备下一次使用。如果对await的方法调用超时,或者阻塞中的线程被中断,那么关卡就被认为是失败的,所有对await未完成的调用都通过BrokenBarrierException终止。
CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。
实例代码如下:
public class CyclicBarrierTest
{
public static void main(String[] args) throws InterruptedException, BrokenBarrierException
{
CyclicBarrier cyclicBarrier=new CyclicBarrier(4);
for(int i=0;i<3;i++)
{
new Writer(cyclicBarrier).start();
}
cyclicBarrier.await();
System.out.println("所有数据均写完!");
}
static class Writer extends Thread
{
CyclicBarrier cyclicBarrier;
public Writer(CyclicBarrier cyclicBarrier)
{
this.cyclicBarrier=cyclicBarrier;
}
@Override
public void run()
{
try
{
Thread.sleep(1000);
System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕");
cyclicBarrier.await();
} catch (Exception e)
{
// TODO 自动生成的 catch 块
e.printStackTrace();
} }
}
}
输出

CyclicBarrier还提供一个更高级的构造函数CyclicBarrier(int parties, Runnable barrierAction),用于在线程到达屏障时,优先执行barrierAction,方便处理更复杂的业务场景。代码如下:
public class CyclicBarrierTest2
{
final static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args)
{
CyclicBarrier end = new CyclicBarrier(2,new MainTask());// 两个工人的协作 Worker worker1 = new Worker("zhang san", 5000, end);
Worker worker2 = new Worker("li si", 8000,end); worker1.start();
worker2.start();
}
static class MainTask implements Runnable
{
public void run()
{
System.out.println("执行最后的任务");
}
}
static class Worker extends Thread
{
String workerName;
int workTime; CyclicBarrier end;
public Worker(String workerName, int workTime, CyclicBarrier end)
{
this.workerName = workerName;
this.workTime = workTime;
this.end = end;
}
public void run()
{
try
{
System.out.println("Worker " + workerName + " do work begin at "+ sdf.format(new Date()));
Thread.sleep(workTime);
System.out.println("Worker " + workerName + " do work complete at " + sdf.format(new Date()));
}
catch (InterruptedException e)
{
// TODO 自动生成的 catch 块
e.printStackTrace();
}
finally
{
try
{
end.await();
} catch (InterruptedException | BrokenBarrierException e)
{
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
}
输出:

三、CyclicBarrier和CountDownLatch的区别
- CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置,因此CyclicBarrier能够处理更为复杂的业务场景,比如如果计算发送错误,可以重置计数器,并让线程重新执行一次。
- CountDownLatch是减计数方式,计数==0时释放所有等待的线程;CyclicBarrier是加计数方式,计数达到构造方法中参数指定的值时释放所有等待的线程。
CountDownLatch当计数到0时,计数无法被重置;CyclicBarrier计数达到指定值时,计数置为0重新开始。
CountDownLatch每次调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响;CyclicBarrier只有一个await()方法,调用await()方法计数加1,若加1后的值不等于构造方法的值,则线程阻塞。 - CountDownLatch: 一个或者是一部分线程 ,等待另外一部线程都完成了,再继续执行 。
CyclicBarrier: 所有线程互相等待完成。
四、参考资料
1、http://ifeve.com/concurrency-cyclicbarrier/
2、Java并发编程实践
【Java并发编程四】关卡的更多相关文章
- Java 并发编程(四):如何保证对象的线程安全性
01.前言 先让我吐一句肺腑之言吧,不说出来会憋出内伤的.<Java 并发编程实战>这本书太特么枯燥了,尽管它被奉为并发编程当中的经典之作,但我还是忍不住.因为第四章"对象的组合 ...
- Java并发编程 (四) 线程安全性
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一.线程安全性-原子性-atomic-1 1.线程安全性 定义: 当某个线程访问某个类时,不管运行时环境 ...
- Java并发编程(四):并发容器(转)
解决并发情况下的容器线程安全问题的.给多线程环境准备一个线程安全的容器对象. 线程安全的容器对象: Vector, Hashtable.线程安全容器对象,都是使用 synchronized 方法实现的 ...
- [Java并发编程(四)] Java volatile 的理论实践
[Java并发编程(四)] Java volatile 的理论实践 摘要 Java 语言中的 volatile 变量可以被看作是一种 "程度较轻的 synchronized":与 ...
- Java并发编程:Java的四种线程池的使用,以及自定义线程工厂
目录 引言 四种线程池 newCachedThreadPool:可缓存的线程池 newFixedThreadPool:定长线程池 newSingleThreadExecutor:单线程线程池 newS ...
- java并发编程笔记(四)——安全发布对象
java并发编程笔记(四)--安全发布对象 发布对象 使一个对象能够被当前范围之外的代码所使用 对象逸出 一种错误的发布.当一个对象还没构造完成时,就使它被其他线程所见 不安全的发布对象 某一个类的构 ...
- 【Java并发编程实战】----- AQS(四):CLH同步队列
在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形.其主要从两方面进行了改造:节点的结构与节点等待机制.在结构上引入了头 ...
- Java并发编程原理与实战四十二:锁与volatile的内存语义
锁与volatile的内存语义 1.锁的内存语义 2.volatile内存语义 3.synchronized内存语义 4.Lock与synchronized的区别 5.ReentrantLock源码实 ...
- Java并发编程原理与实战二十四:简易数据库连接池
public class MyDataSource { private static LinkedList<Connection> pool = new LinkedList<> ...
随机推荐
- 【转】【Nginx】Nginx 入门教程 + 常用配置解析
== Nginx介绍和安装 == Nginx是一个自由.开源.高性能及轻量级的HTTP服务器及反转代理服务器, 其性能与IMAP/POP3代理服务器相当.Nginx以其高性能.稳定.功能丰富.配置简单 ...
- 在Unity场景中控制日夜的轮转
一.介绍 目的:通过在Unity场景中添加C#脚本完成日夜轮转的效果. 软件环境:Unity 2017.3.0f3,VS2013 二.操作过程 通过拖拽场景中的Directional Light我们知 ...
- mysql监控工具sqlprofiler,类似sqlserver的profiler工具
最近无意发现了mysql的客户端监控工具“Nero Profile SQL”,刚开始还不知道怎么使用,经过半小时摸索,现将使用步骤写下来. 背景:开发的时候,如果数据存储层这块使用EF,或者其他orm ...
- Android中的缩略图加载-不浪费一点多余的内存
1. Why,为什么要加载缩略图? 有的时候不需要展示原图,只需展示图片的缩略图,可以节省内存.比如:网易新闻中的图片浏览,左边展示的小狮子图片就是一个缩略图,点击这个图片,才会展示原图. 2. ...
- AFNetWorking能做什么
AFNetwork是一个轻量级的网络请求api类库.是以NSURLConnection, NSOperation和其它方法为基础的. 以下这个样例是用来处理json请求的: NSURL *url = ...
- Http请求的工具
1.火狐的插件 HttpRequester 安装方法:火狐浏览器的最右上角的菜单,打开附件组件 ,搜索:HttpRequester,重启火狐浏览器.在菜单栏的工具下可以看到 HttpRequester ...
- memcached系列之
Slab Allocator的机制分配.管理内存 slabs---->slabs class:chunk size------>申请内存后分配的规格. chunk-->存放记录的单位 ...
- Java常用数据结构之Set之TreeSet
前言 上篇文章我们分析了HashSet,它是基于HashMap实现的,那TreeSet会是怎么实现的呢?没错!和大家想的一样,它是基于TreeMap实现的.所以,TreeSet的源码也很简单,主要还是 ...
- node.js和socket.io实现im
im——Instant Messaging 即时通讯 基本技术原理 (1)通过IM服务器登陆或注销 (2)用户A通过列表找到B,用户B获得消息并与之交谈 (3)通过IM服务器指引建立与B单独的通讯通道 ...
- BarTender怎么打印公式化的三列标签
有小伙伴在业务上有这样的需求:使用BarTender打印一行三列的标签,如下A,B,C三个并排.第一行 A1=a B1=a*2-1 C1=a*2:第二行 A2=a+1 B2=(a+1)*2-1 C2= ...