java多线程系列:Semaphore和Exchanger
本篇文章将介绍Semaphore和Exchanger这两个并发工具类。
Semaphore
信号量(英语:Semaphore)又称为信号标,是一个同步对象,用于保持在0至指定最大值之间的一个计数值。当线程完成一次对该semaphore对象的等待(wait)时,该计数值减一;当线程完成一次对semaphore对象的释放(release)时,计数值加一。当计数值为0,则线程等待该semaphore对象不再能成功直至该semaphore对象变成signaled状态。semaphore对象的计数值大于0,为signaled状态;计数值等于0,为nonsignaled状态.
semaphore对象适用于控制一个仅支持有限个用户的共享资源,是一种不需要使用忙碌等待(busy waiting)的方法。 ----取自维基百科
Semaphore思想在分布式中也有应用,分布式限流就是典型的案例。现在举个小例子来使用Semaphore
案例
在等公交时,遇到人多的时候经常需要排队或者挤进去。
解决方案
利用Semaphore初始化5个许可,每次只能有5个玩家进入,当有玩家退出时,其他玩家才能进入。
先介绍下Semaphore的构造函数和一些方法吧。
Semaphore构造函数
public Semaphore(int permits);
public Semaphore(int permits, boolean fair);
第一个参数permits表示初始化的许可数量,第二个参数表示是否是公平的。
使用Semaphore(int permits)构造函数时,默认使用非公平的
Semaphore常用方法
public void acquire();
public void release();
acquire方法取得许可,release方法表示释放许可。
注:如果多次调用release方法,会增加许可。例如,初始化许可为0,这时调用了两个release方法,Semaphore的许可便会变成2
这两个是最常用的方法,其他的还有acquire相关的方法tryAcquire和acquireUninterruptibly这里就不介绍了。
代码
玩家类
定义一个实现Runnable接口的玩家类
public class Player implements Runnable{
private String playerName;
private Semaphore semaphore;
public Player(String playerName, Semaphore semaphore) {
this.playerName = playerName;
this.semaphore = semaphore;
}
@Override
public void run() {
try {
semaphore.acquire();
System.out.println(playerName+"进入,时间:"+LocalTime.now());
Thread.sleep((long) (3000 * Math.random()));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(playerName+"退出");
semaphore.release();
}
}
}
通过构造函数Player传入玩家名称和Semaphore对象,run方法中先调用acquire方法取得许可,然后睡眠随机时间,最后在finally中调用release方法释放许可。
测试类
先来使用非公平的看看效果,使用非公平的就好比平时的挤公交,谁先在车门口谁先进。如下图(来源于网络)
现在来看看测试代码
public static void main(String[] args) throws IOException {
Semaphore semaphore = new Semaphore(5);
//Semaphore semaphore = new Semaphore(5,true);
ExecutorService service = Executors.newCachedThreadPool();
//模拟100个玩家排队
for (int i = 0; i < 100; i++) {
service.submit(new Player("玩家"+i,semaphore));
}
//关闭线程池
service.shutdown();
//判断线程池是否中断,没有则循环查看当前排队总人数
while (!service.isTerminated()){
System.out.println("当前排队总人数:"+semaphore.getQueueLength());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
如果要切换成公平方式只需将上面初始化Semaphore改为下面的代码即可
Semaphore semaphore = new Semaphore(5,true);
Exchanger
Exchanger主要用于线程间的数据交换。 它提供了一个同步点,在这个同步点,两个线程可以交换数据。
这里写了个两个线程互相交换数据的简单例子,下面ExchangerRunnable在run方法中调用exchange方法将自己的数据传过去。
public class ExchangerRunnable implements Runnable {
private Object data;
private String name;
private Exchanger exchanger;
public ExchangerRunnable(String name, Exchanger exchanger, Object data) {
this.exchanger = exchanger;
this.name = name;
this.data = data;
}
public void run() {
try {
Object previous = this.data;
this.data = this.exchanger.exchange(previous);
System.out.println("名称:" + name + " 之前数据:" + previous + " ,交换之后数据:" + this.data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
接下来看看测试代码
public class Case {
private static final Exchanger exchanger = new Exchanger();
private static ExecutorService service = Executors.newFixedThreadPool(2);
public static void main(String[] args) {
service.submit(new ExchangerRunnable("1", exchanger, "A"));
service.submit(new ExchangerRunnable("2", exchanger, "B"));
service.shutdown();
}
}
定义了只包含两个线程的线程池,然后创建提交两个ExchangerRunnable的类
- 线程名称为1的原始数据时A
- 线程名称为2的原始数据时B
运行测试代码,会得到如下结果
名称:2 之前数据:B ,交换之后数据:A
名称:1 之前数据:A ,交换之后数据:B
欢迎fork、Star、Issue等,谢谢
java多线程系列:Semaphore和Exchanger的更多相关文章
- Java多线程系列--“JUC锁”11之 Semaphore信号量的原理和示例
概要 本章,我们对JUC包中的信号量Semaphore进行学习.内容包括:Semaphore简介Semaphore数据结构Semaphore源码分析(基于JDK1.7.0_40)Semaphore示例 ...
- Java多线程系列--“JUC锁”03之 公平锁(一)
概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...
- Java多线程系列--“JUC锁”01之 框架
本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--“JUC锁”01之 框架02. Java多线程系列--“JUC锁”02之 互斥锁Reentrant ...
- Java多线程系列目录(共43篇)
最近,在研究Java多线程的内容目录,将其内容逐步整理并发布. (一) 基础篇 01. Java多线程系列--“基础篇”01之 基本概念 02. Java多线程系列--“基础篇”02之 常用的实现多线 ...
- Java多线程系列--“JUC锁”07之 LockSupport
概述 本章介绍JUC(java.util.concurrent)包中的LockSupport.内容包括:LockSupport介绍LockSupport函数列表LockSupport参考代码(基于JD ...
- Java多线程系列--“JUC锁”08之 共享锁和ReentrantReadWriteLock
概要 Java的JUC(java.util.concurrent)包中的锁包括"独占锁"和"共享锁".在“Java多线程系列--“JUC锁”02之 互斥锁Ree ...
- Java多线程系列
一.参考文献 1.:Java多线程系列目录 (一) 基础篇 01. Java多线程系列--“基础篇”01之 基本概念 02. Java多线程系列--“基础篇”02之 常用的实现多线程的两种方式 03. ...
- java多线程系列 目录
Java多线程系列1 线程创建以及状态切换 Java多线程系列2 线程常见方法介绍 Java多线程系列3 synchronized 关键词 Java多线程系列4 线程交互(wait和 ...
- Java多线程系列——从菜鸟到入门
持续更新系列. 参考自Java多线程系列目录(共43篇).<Java并发编程实战>.<实战Java高并发程序设计>.<Java并发编程的艺术>. 基础 Java多线 ...
- Java多线程系列目录(转)
转载方便自己学习,转自:Java多线程系列目录(共43篇) http://www.cnblogs.com/skywang12345/p/java_threads_category.html 最近,在研 ...
随机推荐
- [Luogu3674]小清新人渣的本愿
luogu 题意 给你一个序列a,长度为n,有m次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ...
- HDOJ1010 (DFS+奇偶剪枝)
Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Othe ...
- HP 防止cciss设备被DM映射
http://h10025.www1.hp.com/ewfrf/wc/document?cc=cn&lc=zh-hans&dlc=zh-hans&docname=c034933 ...
- SQL简单嵌套查询与非嵌套查询的比较(MSSQL2005)
某天的工作是修复某个项目的bug,接着就发现,其sql极其混乱,有非常多的left join和in操作,还有嵌套查询(只有一个表的嵌套查询).不知道看到过哪里的资料说,嵌套查询速度慢,于是我把全部嵌套 ...
- 使用Jersey和Jetty开发RESTful Web service
Jersey RESTful 框架是开源的RESTful框架, 实现了JAX-RS (JSR 311 & JSR 339) 规范,是JAX-RS的参考实现,并且提供了更多的特性和工具,简化了R ...
- 关于java.lang.ClassNotFoundException
关于java.lang.ClassNotFoundException,在自己的程序中,也出现过好几次了,每次找到原因之后,又会发觉原来是以前处理过的. java.lang.ClassNotFoundE ...
- 机器学习:线性回归法(Linear Regression)
# 注:使用线性回归算法的前提是,假设数据存在线性关系,如果最后求得的准确度R < 0,则说明很可能数据间不存在任何线性关系(也可能是算法中间出现错误),此时就要检查算法或者考虑使用其它算法: ...
- c++ 端口扫描程序
第一.原理 端口扫描的原理很简单,就是建立socket通信,切换不通端口,通过connect函数,如果成功则代表端口开发者,否则端口关闭. 所有需要多socket程序熟悉,本内容是在window环境下 ...
- bytes,packet区别 字节数据包
“包”(Packet)是TCP/IP协议通信传输中的数据单位,一般也称“数据包”.字节(Byte): 字节是通过网络传输信息(或在硬盘或内存中存储信息)的单位. 字节是计算机信息技术用于计量存储容量和 ...
- 问题:sqlserver 跨服务器连接;结果:Sql Server 跨服务器连接
Sql Server 跨服务器连接 用openrowset连接远程SQL或插入数据 --如果只是临时访问,可以直接用openrowset --查询示例 select * from openrowset ...