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 最近,在研 ...
随机推荐
- C#进阶之路(六):表达式进行类的赋值
好久没更新这个系列了,最近看.NET CORE源码的时候,发现他的依赖注入模块的很多地方用了表达式拼接实现的.比如如下代码 private Expression<Func<ServiceP ...
- eclipse Git & maven 安装
JDK安装请自行百度. Maven是免安装的.压缩包解压完成后.如解压后放在D:\Server\maven下.接下来配置maven的环境变量: 系统变量:MAVEN_HOME = D:\Server\ ...
- 「新手向」koa2从起步到填坑
前传 出于兴趣最近开始研究koa2,由于之前有过一些express经验,以为koa还是很好上手的,但是用起来发现还是有些地方容易懵逼,因此整理此文,希望能够帮助到一些新人. 如果你不懂javascri ...
- Unity3D研究院之Assetbundle的原理(六十一)
www.xuanyusong.com/archives/2373 Assetbundle 是Unity Pro提供提供的功能,它可以把多个游戏对象或者资源二进制文件封装到Assetbundle中,提供 ...
- Azure上采用Powershell从已有的VHD创建VM
刚刚的一篇Blog采用Json Template的方式从已有的VHD创建了一台新的VM.由于Json Template封装的比较好,可以改的内容不多. 下面将介绍通过用Powershell来从已有的V ...
- Extjs5.0 学习之路【资源篇】
磨刀不误砍柴工. 先收集资源,然后再开始学习之路. Extjs5.0 文件下载 API-5.0 API离线包 http://cdn.sencha.com/downloads/docs/ext-docs ...
- perform-maintence-on-replica-set-members
https://docs.mongodb.com/v3.0/tutorial/perform-maintence-on-replica-set-members/ 1 oplog 改变大小 --详见mo ...
- idea debug的时候 启动起来超级慢
- java中try{}catch{}和finally{}的执行顺序问题
今天我给大家讲解一下java的的错误和异常处理机制以及相关异常的执行顺序问题.如有不足的地方,欢迎批评指正~ 1.首相简单介绍一下java中的错误(Error)和异常(Exception) 错误和异 ...
- CentOS7 线上环境的一些 配置
上周服务器被攻击导致上面收回了我们服务器的IP,所以这周重新安装部署了服务器,使用centos7系统.为了防止服务器再次被攻击,所以建议以下几点: 1. root密码要复杂一点,尽量字母数字特殊字符都 ...