JDK5新特性之线程同步工具类(三)
一. Semaphore
Semaphore能够控制同一时候訪问资源的线程个数, 比如: 实现一个文件同意的并发訪问数.
Semaphore实现的功能就类似厕全部5个坑, 增加有十个人要上厕所, 那么同一时候仅仅能有5个人能够占用, 当5个人中的不论什么一个人离开后, 当中在等待的另外5个人中就有一个能够占用了. 另外等待的5个人中能够是随机获得优先机会,
也能够使依照先来后到的顺序获得机会, 这取决于构造Semaphore对象时传入的參数选项.
- public class SemaphoreTest {
- public static void main(String[] args) {
- // 创建一个线程池
- ExecutorService service = Executors.newCachedThreadPool();
- final Semaphore sp = new Semaphore(3); // 表示当前有3盏灯(同意3个并发)
- // 启动5个线程
- for (int i = 0; i < 5; i++) {
- service.execute(new Runnable() {
- public void run() {
- try {
- sp.acquire(); // 点亮一盏灯
- // availablePermits: 表示能够使用的灯
- System.out.println("线程" + Thread.currentThread().getName()
- + " 进入,当前已有" + (3 - sp.availablePermits()) + "个并发");
- Thread.sleep((long) (Math.random() * 10000));
- System.out.println("线程" + Thread.currentThread().getName() + " 即将离开");
- sp.release(); // 熄灭一盏灯(释放)
- System.out.println("线程" + Thread.currentThread().getName()
- + " 已离开,当前已有" + (3 - sp.availablePermits()) + "个并发");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- }
- }
- }
单个Semaphore对象能够实现相互排斥锁的功能, 而且能够是由一个线程获得了"锁", 再由还有一个线程释放"锁", 这可应用于死锁恢复的一些场合.
- 线程pool-1-thread-1 进入,当前已有1个并发
- 线程pool-1-thread-2 进入,当前已有2个并发
- 线程pool-1-thread-4 进入,当前已有3个并发
- 线程pool-1-thread-4 即将离开
- 线程pool-1-thread-4 已离开。当前已有2个并发
- 线程pool-1-thread-3 进入。当前已有3个并发
- 线程pool-1-thread-2 即将离开
- 线程pool-1-thread-2 已离开,当前已有2个并发
- 线程pool-1-thread-5 进入。当前已有3个并发
- 线程pool-1-thread-5 即将离开
- 线程pool-1-thread-5 已离开,当前已有2个并发
- 线程pool-1-thread-1 即将离开
- 线程pool-1-thread-1 已离开,当前已有1个并发
- 线程pool-1-thread-3 即将离开
- 线程pool-1-thread-3 已离开,当前已有0个并发
二. CyclicBarrier
表示大家彼此等待。集合好后才開始出发,分散活动后又在指定地点集合碰面。
这就好比整个公司的人员里利用周末时间集体郊游一样。先各自从家出发到公司集合后,再同一时候出发到公园游玩,在指定地点集合后再同一时候開始就餐。
- public class CyclicBarrierTest {
- public static void main(String[] args) {
- // 开启一个线程池
- ExecutorService executorService = Executors.newCachedThreadPool();
- // 參数3: 表示有3个到齐了才干够往下走。否则一直处于等待状态
- final CyclicBarrier cb = new CyclicBarrier(3);
- // 创建3个线程
- for(int i = 0; i < 3; i++){
- executorService.execute(new Runnable(){
- @Override
- public void run(){
- try {
- Thread.sleep((long)(Math.random() * 1000)); // 每一个线程“歇息”的时间不同
- System.out.println("线程" + Thread.currentThread().getName()
- + "即将到达集合地点1。当前已有" + (cb.getNumberWaiting() + 1)
- + "个已经到达," + (cb.getNumberWaiting() == 2 ? "都到齐了,继续前进" : "正在等候"));
- cb.await(); // 先到的等待后到的,当3个都到达时才会继续向下运行
- Thread.sleep((long)(Math.random() * 1000)); // 每一个线程“歇息”的时间不同
- System.out.println("线程" + Thread.currentThread().getName()
- + "即将到达集合地点2。当前已有" + (cb.getNumberWaiting() + 1)
- + "个已经到达," + (cb.getNumberWaiting() == 2 ? "都到齐了。继续前进" : "正在等候"));
- cb.await();
- Thread.sleep((long)(Math.random()*1000)); // 每一个线程“歇息”的时间不同
- System.out.println("线程" + Thread.currentThread().getName()
- + "即将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1)
- + "个已经到达。"+ (cb.getNumberWaiting() == 2 ? "都到齐了。继续前进" : "正在等候"));
- cb.await();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- });
- }
- executorService.shutdown();
- }
- }
三个线程干完各自的任务,在不同的时刻到达集合地点后,就能够接着忙各自的工作去了,再到达新的集合点,再去忙各自的工作。
- 线程pool-1-thread-2即将到达集合地点1,当前已有1个已经到达,正在等候
- 线程pool-1-thread-3即将到达集合地点1,当前已有2个已经到达,正在等候
- 线程pool-1-thread-1即将到达集合地点1,当前已有3个已经到达。都到齐了,继续前进
- 线程pool-1-thread-2即将到达集合地点2。当前已有1个已经到达。正在等候
- 线程pool-1-thread-3即将到达集合地点2,当前已有2个已经到达。正在等候
- 线程pool-1-thread-1即将到达集合地点2。当前已有3个已经到达。都到齐了。继续前进
- 线程pool-1-thread-3即将到达集合地点3,当前已有1个已经到达。正在等候
- 线程pool-1-thread-2即将到达集合地点3,当前已有2个已经到达,正在等候
- 线程pool-1-thread-1即将到达集合地点3,当前已有3个已经到达,都到齐了,继续前进
三. CountDownLatch
宛如倒计时计数器, 调用CountDownLatch对象的countDown方法就将计数器减一, 当计数到达0时, 则全部等待者或单个等待者開始运行.
应用: 裁判一声口令, 运动员同一时候開始奔跑, 当全部运动员都跑到终点后裁判发布结果. 还能够实现一个计划须要多个领导都签字后才干继续向下实施的情况.
- public class CountDownLatchTest {
- public static void main(String[] args) throws Exception {
- ExecutorService service = Executors.newCachedThreadPool();
- // 子计数器, count为1
- final CountDownLatch subCounter = new CountDownLatch(1);
- // 主计数器, count为3
- final CountDownLatch mainCounter = new CountDownLatch(3);
- for(int i = 0; i < 3; i++){
- service.execute(new Runnable() {
- @Override
- public void run() {
- try {
- System.out.println("线程 "+ Thread.currentThread().getName()+"正准备接受命令。");
- subCounter.await(); // 子线程等待
- System.out.println("线程 "+ Thread.currentThread().getName()+"已接受命令!");
- Thread.sleep((long)Math.random() * 10000);
- System.out.println("线程 "+ Thread.currentThread().getName()+"回应命令处理结果!
- ");
- mainCounter.countDown(); // 将计数器身上的计数减1, 当计数为0时, 主线程将開始运行
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- } );
- }
- Thread.sleep((long)Math.random() * 1000);
- System.out.println("线程 "+ Thread.currentThread().getName()+"即将公布命令!");
- subCounter.countDown(); // 将计数器身上的计数减1, 当计数为0时, 子线程開始运行
- System.out.println("线程 "+ Thread.currentThread().getName()+"已发送命令,正在等待结果。");
- mainCounter.await(); // 主线程等待
- System.out.println("线程 "+ Thread.currentThread().getName()+"已收到全部响应结果!
- ");
- service.shutdown();
- }
- }
- 线程 pool-1-thread-1正准备接受命令。
- 线程 pool-1-thread-3正准备接受命令!
- 线程 pool-1-thread-2正准备接受命令!
- 线程 main即将公布命令!
- 线程 main已发送命令。正在等待结果!
- 线程 pool-1-thread-2已接受命令!
- 线程 pool-1-thread-3已接受命令。
- 线程 pool-1-thread-1已接受命令。
- 线程 pool-1-thread-3回应命令处理结果!
- 线程 pool-1-thread-2回应命令处理结果!
- 线程 pool-1-thread-1回应命令处理结果。
- 线程 main已收到全部响应结果!
四. Exchanger
用于实现两个人之间的数据交换, 每一个人在完毕一定的事务后想与对方交换数据, 第一个先拿出数据的人将一直等待第二个人拿着数据到来时, 才干彼此交换数据:
- public class ExchangerTest {
- public static void main(String[] args) {
- ExecutorService service = Executors.newCachedThreadPool();
- final Exchanger exchanger = new Exchanger();
- service.execute(new Runnable() {
- @Override
- public void run() {
- try {
- String data1 = "aaa";
- System.out.println("线程 " + Thread.currentThread().getName() + " 正在把数据: " + data1 + " 换出去!");
- Thread.sleep((long) Math.random() * 10000);
- String data2 = (String) exchanger.exchange(data1);
- System.out.println("线程 " + Thread.currentThread().getName() + " 换回的数据为:" + data2);
- } catch (Exception e) {
- }
- }
- });
- service.execute(new Runnable() {
- @Override
- public void run() {
- try {
- String data1 = "bbb";
- System.out.println("线程 " + Thread.currentThread().getName() + " 正在把数据: " + data1 + " 换出去!");
- Thread.sleep((long) Math.random() * 10000);
- String data2 = (String) exchanger.exchange(data1);
- System.out.println("线程 " + Thread.currentThread().getName() + " 换回的数据为:" + data2);
- } catch (Exception e) {
- }
- }
- });
- }
- }
- 线程 pool-1-thread-1 正在把数据: aaa 换出去!
- 线程 pool-1-thread-2 正在把数据: bbb 换出去!
- 线程 pool-1-thread-1 换回的数据为:bbb
- 线程 pool-1-thread-2 换回的数据为:aaa
JDK5新特性之线程同步工具类(三)的更多相关文章
- JDK5新特性之线程同步集合(五)
一. 传统集合: 传统方式下的Collection在迭代集合时, 不同意对集合进行改动: public class CollectionModifyExceptionTest { public sta ...
- Java核心知识点学习----线程同步工具类,CyclicBarrier学习
线程同步工具类,CyclicBarrier日常开发较少涉及,这里只举一个例子,以做备注.N个人一块出去玩,相约去两个地方,CyclicBarrier的主要作用是等待所有人都汇合了,才往下一站出发. 1 ...
- day27<反射&JDK5新特性>
反射(类的加载概述和加载时机) 反射(类加载器的概述和分类) 反射(反射概述) 反射(Class.forName()读取配置文件举例) 反射(通过反射获取带参构造方法并使用) 反射(通过反射获取成员变 ...
- 线程高级应用-心得6-java5线程并发库中同步工具类(synchronizers),新知识大用途
1.新知识普及 2. Semaphore工具类的使用案例 package com.java5.thread.newSkill; import java.util.concurrent.Executor ...
- 线程同步工具 Semaphore类使用案例
参考博文 : 线程同步工具(一) 线程同步工具(二)控制并发访问多个资源 并发工具类(三)控制并发线程数的Semaphore 使用Semaphore模拟互斥锁 当一个线程想要访问某个共享资源,首先,它 ...
- 线程同步工具 Semaphore类的基础使用
推荐好文: 线程同步工具(一) 线程同步工具(二)控制并发访问多个资源 并发工具类(三)控制并发线程数的Semaphore 简介 Semaphore是基于计数的信号量,可以用来控制同时访问特定资源的线 ...
- java 利用同步工具类控制线程
前言 参考来源:<java并发编程实战> 同步工具类:根据工具类的自身状态来协调线程的控制流.通过同步工具类,来协调线程之间的行为. 可见性:在多线程环境下,当某个属性被其他线程修改后,其 ...
- JDK5 新特性
JDK5新特性目录导航: 自动拆装箱 Foreach 静态导入 可变参数 Var args 枚举 格式化输出 泛型 ProcessBuilder 内省 线程并发库(JUC) 监控和管理虚拟机 元数据 ...
- jdk5新特性
前两天看到jdk10试用版都出来了,才发现自己连1.8都没用过,对不同版本的jdk的新特性也不是太了解,所以想还是百度一下看看人家怎么说然后自己记录总结一下,其中jdk1.8的新特性可以到edu.51 ...
随机推荐
- [luogu2044][NOI2012] 随机数生成器 [矩阵快速幂]
题面: 传送门 思路: 看一眼这个公式: $x\left[n+1\right]=\left(a\ast x\left[n\right]+c\right) mod m$ 递推,数据范围$n\leq 10 ...
- NOIP2017赛前模拟10月30日总结
题目1: n个人参赛(n<=100000),每个人有一个权值··已知两个人权值绝对值之差小于等于K时,两个人都有可能赢,若大于则权值大的人赢···比赛为淘汰制,进行n-1轮·问最后可能赢的人有多 ...
- 【一个比较bug free的二分写法】
lower_bound: [l, r)区间内大于等于val的第一个位置 int lower_bound(int l, int r, int val){ while(l < r){ ); if(a ...
- JAVA 字节流和字符流度读写的区别
java处理文件的类里面,stream结尾都是采用字节流,reader和writer结尾都是采用字符流.两者的区别就是读写的时候一个是按字节读写,一个是按字符. 字符流的底层就是字节流.而字符流主要是 ...
- ofbiz数据库表结构设计(1)- PARTY
ofbiz的精华就在于其数据结构(表结构)的设计.数据结构的通用性也决定了ofbiz几乎可以适用任何企业应用.我们首先来看看PARTY相关的表结构设计. 在ofbiz中,PARTY是个抽象概念,它可以 ...
- c#使用Split分割字符串的几种方法
原文发布时间为:2009-03-07 -- 来源于本人的百度文章 [由搬家工具导入] 最近发现很多人在问在c#中使用Split等分割字符串的方法,今天有时间所以把使用Split等分割字符串的方法做了一 ...
- [论文]A Link-Based Approach to the Cluster Ensemble Problem
论文作者:Natthakan Iam-On, Tossapon Boongoen, Simon Garrett, and Chris Price 下次还是在汇报前先写了论文总结,不然有些点汇报时容易忘 ...
- python日期时间相关
参考: http://www.coder4.com/archives/2239 http://www.cnblogs.com/lhj588/archive/2012/04/23/2466653.htm ...
- IPC最快的方式----共享内存(shared memory)
在linux进程间通信的方式中,共享内存是一种最快的IPC方式.因此,共享内存用于实现进程间大量的数据传输,共享内存的话,会在内存中单独开辟一段内存空间,这段内存空间有自己特有的数据结构,包括访问权限 ...
- FTP上传文件服务器python实现
总结 使用Python的socket和socketserver模块实现ftp文件服务器.不是很难,但在粘包的问题上纠缠了不少时间.解决办法是发送文件信息之后等待一段时间. #!/usr/bin/pyt ...