java concurrent 栅栏,java多线程并发系列之闭锁(Latch)和栅栏(CyclicBarrier)
[一:java并发的开篇 1、在实际应用中,经常用到线程的并发,那为什么需要用到并发呢,不能独自单独的程序处理吗,那很明确的说,多条线程做完成一件事情和一条线程去完成
-闭锁(Latch)
闭锁(Latch):一种同步方法,可以延迟线程的进度直到线程到达某个终点状态。通俗的讲就是,一个闭锁相当于一扇大门,在大门打开之前所有线程都被阻断,一旦大门打开所有线程都将通过,但是一旦大门打开,所有线程都通过了,那么这个闭锁的状态就失效了,门的状态也就不能变了,只能是打开状态。也就是说闭锁的状态是一次性的,它确保在闭锁打开之前所有特定的活动都需要在闭锁打开之后才能完成。
应用场景:
确保某个计算在其需要的所有资源都被初始化之后才继续执行。二元闭锁(包括两个状态)可以用来表示“资源R已经被初始化”,而所有需要R的操作都必须先在这个闭锁上等待。
确保某个服务在其依赖的所有其他服务都已经启动之后才启动。
等待直到某个操作的所有参与者都就绪在继续执行。(例如:多人游戏中需要所有玩家准备才能开始)
CountDownLatch是JDK 5+里面闭锁的一个实现,允许一个或者多个线程等待某个事件的发生。CountDownLatch有一个正数计数器,countDown方法对计数器做减操作,await方法等待计数器达到0。所有await的线程都会阻塞直到计数器为0或者等待线程中断或者超时。
-栅栏(CyclicBarrier)
栅栏类似于闭锁,它能阻塞一组线程直到某个事件发生。 栅栏与闭锁的关键区别在于,所有的线程必须同时到达栅栏位置,才能继续执行。闭锁用于等待事件,而栅栏用于等待其他线程。
场景: 应用一些协议,比如几个家庭成员决定在某个地方集合,所有人在6:00在某地集合,到了以后要等待其他人,之后才能讨论去哪里吃饭。 并行迭代,将一个问题分成很多子问题,当一系列的子问题都解决之后(所有子问题线程都已经await()),此时将栅栏打开,所有子问题线程被释放,而栅栏位置可以留着下次使用。
-例子:两个分别关于CountDownlatch和CyclicBarrier的例子
1、CountDownLatch
有三个工人在为老板干活,这个老板有一个习惯,就是当三个工人把一天的活都干完了的时候,他就来检查所有工人所干的活。记住这个条件:三个工人先全部干完活,老板才检查。所以在这里用Java代码设计两个类,Worker代表工人,Boss代表老板,具体的代码实现如下:
工人:
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("工人活都干完了,老板开始检查了!"); } }
测试代码:[以前在<>一书中看到有一节的标题是“CyclicBarrier让多线程齐步走”,觉得这标题挺不错的,所以在写这篇博文的时候也采用了这
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);
}
await方法调用了AbstractQueuedSynchronizer中的acquireSharedInterruptibly
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();
}
}
上面dowait方法中有一个index,index=--count而count的值在源码中来自
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()(唤醒其他线程之前执行)
[一、多线程1、操作系统有两个容易混淆的概念,进程和线程。进程:一个计算机程序的运行实例,包含了需要执行的指令;有自己的独立地址空间,包含程序内容和数据;不同进程
java concurrent 栅栏,java多线程并发系列之闭锁(Latch)和栅栏(CyclicBarrier)相关推荐
- java线程栅栏_Java多线程并发系列之闭锁(Latch)和栅栏(CyclicBarrier)
今天项目上遇到一个多线程任务问题,大概图文描述一下: 1.前端需要及时返回任务状态 2.后台开了一个任务线程去执行具体的业务,业务包括四个部分,四个部分全部完成才算完成 3.业务中某些耗时的或者需要多 ...
- java的知识点32——多线程 并发同步的 性能分析、快乐影院 订票操作
多线程 并发 同步 性能分析 /*** 线程安全: 在并发时保证数据的正确性.效率尽可能高* synchronized* 1.同步方法* 2.同步块* @author Administrator ...
- java线程钥匙_Java多线程并发编程/锁的理解
一.前言 最近项目遇到多线程并发的情景(并发抢单&恢复库存并行),代码在正常情况下运行没有什么问题,在高并发压测下会出现:库存超发/总库存与sku库存对不上等各种问题. 在运用了 限流/加锁等 ...
- 网易云课堂微专业--Java高级开发工程师--多线程并发编程--学习笔记(二)
文章目录 第一章 多线程并发编程 第二节 线程安全问题 1.2.1 线程安全之可见性问题 多线程中的问题 从内存结构到内存模型 工作内存缓存 指令重排序 内存模型的含义 Shared Variable ...
- java 容器 线程_JAVA多线程并发容器
1.ArrayList线程不安全:CopyOnWriteArrayList线程安全 package concurrent; import java.util.ArrayList; import jav ...
- java concurrent 框架,java.util.concurrent 包下的 Synchronizer 框架
看完书 java concurrency in practice 当然是想找点啥好玩的东东玩玩. 当看到了Doug Lee 的论文 << The java.util.concurrent ...
- 信号量(Semaphore)、闭锁(Latch)、栅栏(Barrier)
目录 1.信号量(Semaphore) 描述 场景 Semaphore 2.闭锁(Latch) 描述 场景 CountDownLatch 3.栅栏(Barrier) 描述 场景 CyclicBarri ...
- java线程池_Java多线程并发:线程基本方法+线程池原理+阻塞队列原理技术分享...
线程基本方法有哪些? 线程相关的基本方法有 wait,notify,notifyAll,sleep,join,yield 等. 线程等待(wait) 调用该方法的线程进入 WAITING 状态,只有等 ...
- java aqs源码_Java并发系列-AQS源码学习
AQS框架学习 Node节点 状态表示 cancelled:表明当前线程已经放弃锁 signal:表明当前线程正在运行,它后面的线程等着被它唤醒 condition:表明当前线程正在有条件的等待 pr ...
最新文章
- R语言可视化堆叠(stack)的条形图并通过另外一个分类变量分离(dodge)条形图(stacking by one variable and dodging by another)实战
- 2013 多校联合4 1011 Fliping game (hdu 4642)
- ubuntu配置GDB
- Eclipse 创建第一个 springboot 应用
- java jtextarea滚动条下滑,关于JTextArea的滚动条问题
- 雪城大学信息安全讲义 一、引言
- BZOJ5336 TJOI2018 party 【状压DP】*
- 简单的网页制作_制作简单网页物体
- Office groove系统的术语
- USACO 2.1 海明码(DFS)
- 2017年网站建设公司现状分析
- 【java】超市购物小程序
- excel如何批量制作二维码?
- cass有坐标文件生成里程文件_南方CASS里程文件生成
- 福州三中 计算机竞赛,第一时间对话钟子谦!世界信息学奥赛金牌得主载誉归来!...
- 高德地图API之定位API
- SD卡格式化|SD卡数据恢复技巧
- 深度学习入门——利用卷积神经网络训练CIFAR—10数据集
- 3Dmax场景小房子—打造完整还原游戏场景
- log4j2的一些配置,为某个类某个方法单独文件打印日志,定时删除日志和springboot的logback日志单独类打印
热门文章
- Qt实现文字滚动、翻动动画
- stm32看门狗工作原理
- python3.4勾股定理代码_趣味编程,用Scratch和Python画勾股树
- 《腾讯传》对于个人的一点启发
- java游戏应龙女魃转世_女魃和应龙真的有故事?应龙与女魃的爱情故事揭秘
- /etc/fstab 只读无法修改的解决办法(转)
- 代码评测后结果的OI专业术语
- visual basic VB.NET实例系列教程第二节(好玩又有趣的龟兔赛跑程序)
- VC++ socket编程实例
- Node.js学习笔记 更新完毕 2022 coderwhyWEB前端体系课