多线程003 - 再谈CyclicBarrier
java.util.concurrent.CyclicBarrier也是JDK 1.5提供的一个同步辅助类(为什么用也呢?參见再谈CountDownLatch)。它同意一组线程互相等待,直到到达某个临界点(a common barrier point,翻译成公共障碍点、公共栅栏点都不够传神,直接用临界点吧)。在某个程序中,一组固定大小的线程必须互相等待时。CyclicBarrier将起非常大的作用。由于在等待线程被释放后,这个临界点能够重用。所以说是循环的。
CyclicBarrier支持一个可选的Runnable。在一组线程中的最后一个线程完毕之后、释放全部线程之前,该Runnable在屏障点执行一次(每循环一次Runnable执行一次)。这样的方式能够用来在下一波继续执行的线程执行之前更新共享状态(比方下一波僵尸来之前。检查武器弹药)。
CountDownLatch与CyclicBarrier
CountDownLatch是不可以反复使用的。是一次性的,其锁定一经打开。就不可以在反复使用。
就像引线。点燃后就在燃烧降低。燃烧完了就不能再次使用了。
CyclicBarrier是一种循环的方式进行锁定,这次锁定被打开之后,还可以反复计数。再次使用。就像沙漏。这次漏完了。倒过来接着漏。
另一点是两者之间非常大的差别,就是CountDownLatch在等待子线程的过程中,会锁定主线程,而CyclicBarrier不会锁定主线程,仅仅是在全部子线程结束后。依据定义运行其可选的Runnable线程。
所以在这两种辅助类中进行选择时,可以非常明显进行区分。
CyclicBarrier实例
能够考虑这么一种情况,我们须要向数据库导入一些数据,没导入几条希望能进行一次计时,便于我们查看。由于实现比較简单,直接上代码:
package howe.demo.thread.cyclicbarrier; import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit; /**
* @author liuxinghao
* @version 1.0 Created on 2014年9月17日
*/
public class CyclicBarrierTest {
public static void main(String[] args) throws InterruptedException {
final long start = System.currentTimeMillis();
final CyclicBarrier barrier = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
long end = System.currentTimeMillis();
System.out.println("导入" + 3 + "条数据,至此总共用时:" + (end - start)
+ "毫秒");
}
}); for (int i = 0; i < 9; i++) {
final int threadID = i + 1;
new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(new Random().nextInt(10));// 模拟业务操作
System.out.println(threadID + "完毕导入操作。 ");
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}).start();
}
System.out.println("====主线程结束====");
}
}
运行结果为:
====主线程结束====
4完毕导入操作。 2完毕导入操作。
1完毕导入操作。
导入3条数据,至此总共用时:4006毫秒
5完毕导入操作。
6完毕导入操作。
8完毕导入操作。
导入3条数据。至此总共用时:4007毫秒
3完毕导入操作。 0完毕导入操作。
7完毕导入操作。
导入3条数据。至此总共用时:8006毫秒
程序没导入3条会进行一次计时,统计已经运行的时间。
假设CyclicBarrier构造函数的数字和for循环的次数相等的话,这个就是总共用时。
扩展
考虑一下上面的样例,假设for循环的次数不是CyclicBarrier监听次数的整数倍,比方是10。那运行结果将会是:
====主线程结束====
2完毕导入操作。
5完毕导入操作。 4完毕导入操作。 导入3条数据,至此总共用时:4005毫秒
8完毕导入操作。
1完毕导入操作。 3完毕导入操作。
导入3条数据。至此总共用时:5005毫秒
7完毕导入操作。 6完毕导入操作。 0完毕导入操作。 导入3条数据。至此总共用时:8005毫秒
9完毕导入操作。
在打印完“9完毕导入操作。
”之后,将一直等待。
在这里能够通过barrier.getNumberWaiting()查看还差多少个线程达到屏障点。
假设出现这样的情况。那就须要和CountDownLatch配合使用了。当子线程所有运行完。有推断barrier.getNumberWaiting()不等于0,则调用barrier.reset()重置。这个时候将会触发BrokenBarrierException异常,可是将结束整个过程。
改动的代码例如以下:
package howe.demo.thread.cyclicbarrier; import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit; /**
* @author liuxinghao
* @version 1.0 Created on 2014年9月17日
*/
public class CyclicBarrierTest {
public static void main(String[] args) throws InterruptedException {
final long start = System.currentTimeMillis();
final CountDownLatch count = new CountDownLatch(10);
final CyclicBarrier barrier = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
long end = System.currentTimeMillis();
System.out.println("导入" + 3 + "条数据,至此总共用时:" + (end - start)
+ "毫秒");
}
}); for (int i = 0; i < 10; i++) {
final int threadID = i + 1;
new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(new Random().nextInt(10));// 模拟业务操作
System.out.println(threadID + "完毕导入操作。 ");
count.countDown();
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
System.out.println("触发BrokenBarrierException异常。");
}
}
}).start();
}
count.await(); if(barrier.getNumberWaiting() != 0) {
System.out.println("不是整数倍。 都已运行完,重置CyclicBarrier。 ");
barrier.reset();
} System.out.println("====主线程结束====");
}
}
运行结果为:
3完毕导入操作。
9完毕导入操作。 6完毕导入操作。
导入3条数据,至此总共用时:3005毫秒
8完毕导入操作。
5完毕导入操作。 10完毕导入操作。
导入3条数据。至此总共用时:7005毫秒
1完毕导入操作。
7完毕导入操作。
4完毕导入操作。
2完毕导入操作。
导入3条数据,至此总共用时:9005毫秒
不是整数倍。都已运行完,重置CyclicBarrier。
====主线程结束====
触发BrokenBarrierException异常。
使用barrier.reset()进行重置,由于CyclicBarrier是一个循环,开头就是结尾,所以重置也能够理解为直接完毕。
另外。由于使用了CountDownLatch。所以主线程会锁定,直到线程通过count.await()向下运行。
多线程003 - 再谈CyclicBarrier的更多相关文章
- 沉淀再出发:再谈java的多线程机制
沉淀再出发:再谈java的多线程机制 一.前言 自从我们学习了操作系统之后,对于其中的线程和进程就有了非常深刻的理解,但是,我们可能在C,C++语言之中尝试过这些机制,并且做过相应的实验,但是对于ja ...
- 再谈多线程模型之生产者消费者(总结)(c++11实现)
0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生产者消费 ...
- 再谈多线程模型之生产者消费者(多生产者和多消费者 )(c++11实现)
0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生产者消费 ...
- 再谈多线程模型之生产者消费者(多生产者和单一消费者 )(c++11实现)
0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生产者消费 ...
- 再谈多线程模型之生产者消费者(单一生产者和多消费者 )(c++11实现)
0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生产者消费 ...
- 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现)
0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现)[本文] 再谈多线程模型之生 ...
- 再谈多线程模型之生产者消费者(基础概念)(c++11实现)
0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现)[本文] 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生 ...
- Another Look at Events(再谈Events)
转载:http://www.qtcn.org/bbs/simple/?t31383.html Another Look at Events(再谈Events) 最近在学习Qt事件处理的时候发现一篇很不 ...
- 再谈DOMContentLoaded与渲染阻塞—分析html页面事件与资源加载
浏览器的多线程中,有的线程负责加载资源,有的线程负责执行脚本,有的线程负责渲染界面,有的线程负责轮询.监听用户事件. 这些线程,根据浏览器自身特点以及web标准等等,有的会被浏览器特意的阻塞.两个很明 ...
随机推荐
- 关于 xftp 上传文件时,仅仅是上传了0字节的问题
有两次,上传的时候出现了问题.能上传.可是上传过去的文件都是0字节.查看了各种配置,都是正常的:百思不得解: 后来想起近期在linuxserver运行apt-get update时,中间曾失败过,于是 ...
- 关于static的使用
在我们写类写方法的时候,通常会看到有的时候是静态的方法,有的则是动态的,那么问题来了,什么时候该加static什么时候不加static?这里的区别有多大那?那么加不加static取决与这个方法的特征与 ...
- Shell脚本:推断用户和用户组是否已经存在/创建用户和用户组
通常作为一个应用程序的部署脚本,開始的第一项工作是为当前应用创建一个专用(dedicated)的用户和用户组.这个脚本非常easy.这里贴一个參考样本: #!/bin/sh user=test_use ...
- HDOJ 题目3518 Boring counting(后缀数组,求不重叠反复次数最少为2的子串种类数)
Boring counting Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- POJ 2239 匈牙利算法
思路:最大匹配 也是很裸的一道题-. // by SiriusRen #include <cstdio> #include <cstring> #include <alg ...
- 基于nginx的最基础的TCP代理,经过测试可通!
测试操作系统为win7,nginx版本为1.9.4. 在本机上编写java程序一个socket服务类SocketServer,监听端口为8889, (增加了一个SocketServerThread线程 ...
- javascript中构造函数的说明
1.1 构造函数是一个模板 构造函数,是一种函数,主要用来在创建对象时对 对象 进行初始化(即为对象成员变量赋初始值),并且总是与new运算符一起使用. 1.2 new 运算符 new运算符创建一个新 ...
- Android ImageView 替换图片
网上找了半天,找到的都是错的,都不是我想要的效果.我想要的是点击一个图片后,图片被替换. 通过一下方法可以实现:“v”是ImageView对象,“image_name”是替换后的图片资源 ((Imag ...
- SQL Server-聚焦移除Bookmark Lookup、RID Lookup、Key Lookup提高SQL查询性能
前言 前面几节都是讲的基础内容,本节我们讲讲索引性能优化,当对大数据进行处理时首先想到的就是索引,一旦遇到这样的问题则手忙脚乱,各种查资料,为何平常不扎实基本功呢,我们由浅入深,简短的内容,深入的 ...
- Caffe Batch Normalization推导
Caffe BatchNormalization 推导 总所周知,BatchNormalization通过对数据分布进行归一化处理,从而使得网络的训练能够快速并简单,在一定程度上还能防止网络的过拟合, ...