java多线程并发系列之闭锁(Latch)和栅栏(CyclicBarrier)
-闭锁(Latch)
- 确保某个计算在其需要的所有资源都被初始化之后才继续执行。二元闭锁(包括两个状态)可以用来表示“资源R已经被初始化”,而所有需要R的操作都必须先在这个闭锁上等待。
- 确保某个服务在其依赖的所有其他服务都已经启动之后才启动。
- 等待直到某个操作的所有参与者都就绪在继续执行。(例如:多人游戏中需要所有玩家准备才能开始)
-栅栏(CyclicBarrier)
-例子:两个分别关于CountDownlatch和CyclicBarrier的例子
1、CountDownLatch
工人:
package LatchAndCyclicBarrier;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Work implements Runnable{
private CountDownLatch downLatch;
private String name;
public Work(CountDownLatch downLatch, String name){
this.downLatch = downLatch;
this.name = name;
}
public void run() {
this.doWork();
try{
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
}catch(InterruptedException ie){
}
System.out.println(this.name + "活干完了!");
this.downLatch.countDown();
}
private void doWork(){
System.out.println(this.name + "正在干活!");
}
}
老板:
package LatchAndCyclicBarrier;
import java.util.concurrent.CountDownLatch;
public class Boss implements Runnable{
private CountDownLatch downLatch;
public Boss(CountDownLatch downLatch){
this.downLatch = downLatch;
}
public void run() {
System.out.println("老板正在等所有的工人干完活......");
try {
this.downLatch.await();
} catch (InterruptedException e) {
}
System.out.println("工人活都干完了,老板开始检查了!");
}
}
测试代码:
package LatchAndCyclicBarrier;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestLatch {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
CountDownLatch latch = new CountDownLatch(3);
Work w1 = new Work(latch,"张三");
Work w2 = new Work(latch,"李四");
Work w3 = new Work(latch,"王二");
Boss boss = new Boss(latch);
executor.execute(w3);
executor.execute(w2);
executor.execute(w1);
executor.execute(boss);
executor.shutdown();
}
}
执行结果:
李四正在干活!
老板正在等所有的工人干完活......
王二正在干活!
张三正在干活!
李四活干完了!
王二活干完了!
张三活干完了!
工人活都干完了,老板开始检查了!
2、CyclicBarrier
package LatchAndCyclicBarrier;
import java.util.concurrent.CyclicBarrier;
public class CycWork implements Runnable {
private CyclicBarrier cyclicBarrier ;
private String name ;
public CycWork(CyclicBarrier cyclicBarrier,String name)
{
this .name =name;
this .cyclicBarrier =cyclicBarrier;
}
@Override
public void run() {
// TODO Auto-generated method stub
System. out .println(name +"正在打桩,毕竟不轻松。。。。。" );
try {
Thread. sleep(5000);
System. out .println(name +"不容易,终于把桩打完了。。。。" );
cyclicBarrier .await();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
System. out .println(name +":其他逗b把桩都打完了,又得忙活了。。。" );
}
}
测试程序
package LatchAndCyclicBarrier;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CycTest {
public static void main(String[] args)
{
ExecutorService executorpool=Executors. newFixedThreadPool(3);
CyclicBarrier cyclicBarrier= new CyclicBarrier(3);
CycWork work1= new CycWork(cyclicBarrier, "张三" );
CycWork work2= new CycWork(cyclicBarrier, "李四" );
CycWork work3= new CycWork(cyclicBarrier, "王五" );
executorpool.execute(work1);
executorpool.execute(work2);
executorpool.execute(work3);
executorpool.shutdown();
}
}
运行结果:
李四正在打桩,毕竟不轻松。。。。。
张三正在打桩,毕竟不轻松。。。。。
王五正在打桩,毕竟不轻松。。。。。
李四不容易,终于把桩打完了。。。。
张三不容易,终于把桩打完了。。。。
王五不容易,终于把桩打完了。。。。
王五:其他逗b把桩都打完了,又得忙活了。。。
李四:其他逗b把桩都打完了,又得忙活了。。。
张三:其他逗b把桩都打完了,又得忙活了。。。
CountDownlatch和CyclicBarrierde 源码部分
1、CountDownLatch中的两个关键方法
public void countDown() { //对计数器减一 表示有一个事件已经发生了
sync.releaseShared(1);
}
public void await() throws InterruptedException { //等到计数器为0
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly (int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
public final boolean releaseShared (int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true ;
}
return false ;
}
protected boolean tryReleaseShared (int arg) {
throw new UnsupportedOperationException();
}
2、CyclicBarrier中的await()方法
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen;
}
}
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;
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
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();
}
}
count = parties;
提到 parties就不得不看看构造函数了
public CyclicBarrier(int parties) {
this(parties, null);
}
如上例子,我们构造了CyclicBarrier(3)那么此时的 count值为3,接着dowait源码,当index==0时,后面执行的
final Runnable command = barrierCommand;
其实是可以设置的,这个Runnable可以传进来,当我们希望所有线程都达到某一时刻之后,用什么线程执行接下来的工作,当没有传Runnable进来时,就继续执行(唤醒其他线程),否则就runnable.run()(唤醒其他线程之前执行)
java多线程并发系列之闭锁(Latch)和栅栏(CyclicBarrier)的更多相关文章
- Java多线程并发系列之闭锁(Latch)和栅栏(CyclicBarrier)
JAVA并发包中有三个类用于同步一批线程的行为,分别是闭锁(Latch),信号灯(Semaphore)和栅栏(CyclicBarrier).本贴主要说明闭锁(Latch)和栅栏(CyclicBarri ...
- 并发编程 04——闭锁CountDownLatch 与 栅栏CyclicBarrier
Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...
- java 多线程并发系列之 生产者消费者模式的两种实现
在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题.该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度. 为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据 ...
- java高并发系列 - 第16天:JUC中等待多线程完成的工具类CountDownLatch,必备技能
这是java高并发系列第16篇文章. 本篇内容 介绍CountDownLatch及使用场景 提供几个示例介绍CountDownLatch的使用 手写一个并行处理任务的工具类 假如有这样一个需求,当我们 ...
- 从火箭发场景来学习Java多线程并发闭锁对象
从火箭发场景来学习Java多线程并发闭锁对象 倒计时器场景 在我们开发过程中,有时候会使用到倒计时计数器.最简单的是:int size = 5; 执行后,size—这种方式来实现.但是在多线程并发的情 ...
- Java高并发系列——检视阅读
Java高并发系列--检视阅读 参考 java高并发系列 liaoxuefeng Java教程 CompletableFuture AQS原理没讲,需要找资料补充. JUC中常见的集合原来没讲,比如C ...
- Java 多线程并发编程一览笔录
Java 多线程并发编程一览笔录 知识体系图: 1.线程是什么? 线程是进程中独立运行的子任务. 2.创建线程的方式 方式一:将类声明为 Thread 的子类.该子类应重写 Thread 类的 run ...
- Java多线程并发07——锁在Java中的实现
上一篇文章中,我们已经介绍过了各种锁,让各位对锁有了一定的了解.接下来将为各位介绍锁在Java中的实现.关注我的公众号「Java面典」了解更多 Java 相关知识点. 在 Java 中主要通过使用sy ...
- [转]Java多线程干货系列—(一)Java多线程基础
Java多线程干货系列—(一)Java多线程基础 字数7618 阅读1875 评论21 喜欢86 前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们 ...
随机推荐
- 解题:CTSC 2008 祭祀
题面 洛谷要求输出方案,懒得写了,但是还是放一下链接看看吧 (虽然现在二分图已经过气了=.=) 要求最长反链,最长反链=最小链覆盖,先Floyd传递闭包之后链覆盖就变成了边覆盖,然后最小边覆盖=总点数 ...
- redis 中用正则找key
获取 redis 中所有的 key 可用使用 *. redis 127.0.0.1:6379> KEYS * 1) "w3c3" 2) "w3c1" 3) ...
- 自己写的一个Vue
下面这里是我自己写的一个小型的vue,原理就是proxy: //Proxy天生没有prototype,因此要加上,不然extends会报错 Proxy.prototype = Proxy.protot ...
- 20181108 Apache Commons Lang
工具类 org.apache.commons.lang3 AnnotationUtils ArchUtils ArrayUtils BooleanUtils CharSetUtils CharUtil ...
- Spark记录-Scala字符串
Scala字符串 在Scala中的字符串和Java中的一样,字符串是一个不可变的对象,也就是一个不能修改的对象.可以修改的对象,如数组,称为可变对象.字符串是非常有用的对象,在本节的最后部分,我们将介 ...
- Spring Boot 源码分析 数据源 + Mybatis 配置
公司今年开始使用 Spring Boot 开发,当然使用 Spring Boot 也是大势所趋,尤其是现在微服务的趋向,当然是选择基于Spring Boot 的 Spring Cloud.(所谓的 S ...
- bzoj千题计划211:bzoj1996: [Hnoi2010]chorus 合唱队
http://www.lydsy.com/JudgeOnline/problem.php?id=1996 f[i][j][0/1] 表示已经排出队形中的[i,j],最后一个插入的人在[i,j]的i或j ...
- 何凯文每日一句打卡||DAY9
- ASP.net学习总结
学习ASP.net又一次接触了B/S开发.下面先通过一张图对ASP.net有一个宏观结构的总结.之后将详细介绍ASP.net中的六大对象. 1.Request从客户端得到数据,包括基于表单的数据和通过 ...
- # 20155337 2016-2017-2 《Java程序设计》第六周学习总结
20155337 2016-2017-2 <Java程序设计>第六周学习总结 教材学习内容总结 •串流(Stream): 数据有来源及目的地,衔接两者的是串流对象.如果要将数据从来源取出, ...