Java并发编程之CountDownLatch,CyclicBarrier实现一组线程相互等待、唤醒
java多线程应用场景不少,有时自己编写代码又不太容易实现,好在concurrent包提供了不少实现类,还有google的guava包更是提供了一些最佳实践,这让我们在面对一些多线程的场景时,有了不少的选择。
这里主要是看几个涉及到多线程等待的工具类。
一 CountDownLatch 一个或多个线程等待其他线程达到某一个目标后,再进行自己的下一步工作。而被等待的“其他线程”达到这个目标后,也继续自己下面的任务
public CountDownLatch(int count) { }; //参数count为计数值
public void await() throws InterruptedException { }; //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public void countDown() { }; //将count值减1
工作原理就是让“其他线程”在合适的地方进行await等待,直到所有线程达到了某一个目标,然后再一起释放。
import java.util.Random;
import java.util.concurrent.CountDownLatch;
/**
* Created by wuwf on 17/7/17.
* 一个线程或多个线程等待其他线程运行达到某一目标后进行自己的下一步工作,而被等待的“其他线程”达到这个目标后继续自己下面的任务。
* <p/>
*
*/
public class TestCountDownLatch {
private CountDownLatch countDownLatch = new CountDownLatch(4);
public static void main(String[] args) {
TestCountDownLatch testCountDownLatch = new TestCountDownLatch();
testCountDownLatch.begin();
}
/**
* 运动员
*/
private class Runner implements Runnable {
private int result;
public Runner(int result) {
this.result = result;
}
@Override
public void run() {
try {
//模拟跑了多少秒,1-3之间随机一个数
Thread.sleep(result * 1000);
System.out.println("运动员" + Thread.currentThread().getId() + "跑了" + result + "秒");
//跑完了就计数器减1
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void begin() {
System.out.println("赛跑开始");
Random random = new Random(System.currentTimeMillis());
for (int i = 0; i < 4; i++) {
//随机设置每个运动员跑多少秒结束
int result = random.nextInt(3) + 1;
new Thread(new Runner(result)).start();
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有人都跑完了,裁判开始算成绩");
}
}
这段代码就是一个主线程,等待其他多个子线程完成某个任务后,再去执行下面的逻辑。
模拟并发的代码
import java.util.concurrent.CountDownLatch;
/**
* Created by wuwf on 17/7/18.
* 模拟N个线程同时启动
*/
public class TestManyThread {
private CountDownLatch countDownLatch = new CountDownLatch(200);
public static void main(String[] args) {
new TestManyThread().begin();
}
public void begin() {
for (int i = 0; i < 200; i++) {
new Thread(new UserThread()).start();
countDownLatch.countDown();
}
try {
Thread.sleep(2000);
System.out.println("线程并发");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private class UserThread implements Runnable {
@Override
public void run() {
try {
//等待所有线程
countDownLatch.await();
//TODO 在这里做客户端请求,譬如访问数据库之类的操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
需要注意,上面两个例子是不同的方式,一个是主线程等待其他线程达到某个目标后,自己再去完成一件事;第二个例子是多个线程达到某个目标后,继续完成各自的后续任务。
其中由第二个例子引申出下一个并发工具类。
二 CyclicBarrier 实现让一组线程等待至某个状态之后再全部同时执行,而且当所有等待线程被释放后,CyclicBarrier可以被重复使用。
public CyclicBarrier(int parties, Runnable barrierAction) {
}
public CyclicBarrier(int parties) {
}
parties代表让多少个线程等待,Runnable属性是一个新线程,代表所有线程达到状态、等待完毕后,会执行的任务。
同样的也有两个await方法
public int await() throws InterruptedException, BrokenBarrierException { };
public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException { };
第一个代表线程挂起开始等待,一直等到达到目标状态,第二个代表等待一段指定的时间后,如果还没释放,就直接继续执行,不await了。
import java.util.concurrent.CyclicBarrier;
/**
* Created by wuwf on 17/7/18.
*/
public class TestCyclicBarrier {
private CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
public static void main(String[] args) {
new TestCyclicBarrier().begin();
}
public void begin() {
for (int i = 0; i < 5; i++) {
new Thread(new Student()).start();
}
}
private class Student implements Runnable {
@Override
public void run() {
try {
System.out.println("学生" + Thread.currentThread().getId() + "正在赶往XX饭店的路上");
Thread.sleep(2000);
//到了就等着,等其他人都到了,就进饭店
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("大家都到了,进去吃饭吧!");
}
}
}
Java并发编程之CountDownLatch,CyclicBarrier实现一组线程相互等待、唤醒的更多相关文章
- Java 并发编程中的 CyclicBarrier 用于一组线程互相等待
Java 5 引入的 Concurrent 并发库软件包中的 CyclicBarrier 是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point) ...
- Java并发编程之CountDownLatch
一.场景描述 在多线程程序设计中,经常会遇到一个线程等待一个或多个线程的场景 例如:百米赛跑,十名运动员同时起跑,由于速度的快慢,肯定有先到达和后到达的,而终点有个统计成绩的仪器,当所有选手到达终点时 ...
- Java并发编程之CountDownLatch的用法
一.含义 CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能.CountDownLatch是一个同步的辅助类,它可以允许一个或多个线程等待, ...
- Java并发编程之CyclicBarrier
一.场景描述 有四个游戏玩家玩游戏,游戏有三个关卡,每个关卡必须要所有玩家都到达后才能允许通过.其实这个场景里的玩家中如果有玩家A先到了关卡1,他必须等到其他所有玩家都到达关卡1时才能通过,也就是说线 ...
- Java并发编程之CAS
CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替 ...
- Java并发编程之CAS第一篇-什么是CAS
Java并发编程之CAS第一篇-什么是CAS 通过前面几篇的学习,我们对并发编程两个高频知识点了解了其中的一个—volatitl.从这一篇文章开始,我们将要学习另一个知识点—CAS.本篇是<凯哥 ...
- Java并发编程之CAS二源码追根溯源
Java并发编程之CAS二源码追根溯源 在上一篇文章中,我们知道了什么是CAS以及CAS的执行流程,在本篇文章中,我们将跟着源码一步一步的查看CAS最底层实现原理. 本篇是<凯哥(凯哥Java: ...
- Java并发编程之CAS第三篇-CAS的缺点及解决办法
Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...
- Java并发编程之set集合的线程安全类你知道吗
Java并发编程之-set集合的线程安全类 Java中set集合怎么保证线程安全,这种方式你知道吗? 在Java中set集合是 本篇是<凯哥(凯哥Java:kagejava)并发编程学习> ...
随机推荐
- RocEDU.阅读.写作《苏菲的世界》书摘(三)
根据柏拉图的说法,人是一种具有双重性质的生物.我们的身体是"流动"的,与感官的世界不可分割,并且其命运与世界上其他每一件事物(如肥皂泡)都相同.我们所有的感官都是以身体为基础,因此 ...
- 从零开始玩转JMX(二)——Condition
Notification 一个MBean提供的管理接口允许代理对其管理资源进行控制和配置.然而,对管理复杂的分布式系统来说,这些接口知识提供了一部分功能.通常,管理应用程序需要对状态变化或者当特别情况 ...
- SQL Server-深入剖析统计信息
转自: http://www.cnblogs.com/zhijianliutang/p/4190669.html 概念理解 关于SQL Server中的统计信息,在联机丛书中是这样解释的 查询优化 ...
- mybatis的操作数据库基础
1.domain类 package com.xiaostudy.mybatis.domain; /** * @desc domain类 * @author xiaostudy * */ public ...
- 关于推荐库位 java前端与SQL语句后面的结合
----------------------------------------------------------------------------------- select a1.id,a1. ...
- centos7 VNC安装
root用户: yum install tigervnc-server .service vim /etc/systemd/system/vncserver@:.service .service vn ...
- angularjs1 自定义图片查看器(可旋转、放大、缩小、拖拽)
笔记: angularjs1 制作自定义图片查看器(可旋转.放大.缩小.拖拽) 2018-01-12 更新 可以在我的博客 查看我 已经封装好的 纯 js写的图片查看器插件 博客链接 懒得把 ...
- PHP数组合并:[“+”运算符]、[array_merge]、[array_merge_recursive]区别
1.“+”运算符规则: 当两个数组的键名是数字键名或者字符串键名 $c = $a + $b 在$a后追加($b在$a中不存在的键名)键名和值注意: 1.不覆盖,只是追加不存在的键名和对应的值 2.键名 ...
- 前端打印功能实现及css设置
首先是使用下边代码,实现js局部打印功能.参数dom为需要打印的节点,为了保证页面功能的单一性,最好弹出一个新的预览页面完成打印功能. function print(dom){ var body = ...
- [Vue]组件——插槽:slot(匿名插槽,具名插槽)与slot-scope(作用域插槽)
1.单个插槽 | 匿名插槽 1.1<navigation-link> 子组件定义为: <a v-bind:href="url" class="nav-l ...