java多线程-信号量
Semaphore(信号量)是一个线程同步结构,用于在线程间传递信号,以避免出现信号丢失,或者像锁一样用于保护一个关键区域。自从 5.0 开始,jdk 在 java.util.concurrent 包里提供了 Semaphore 的官方实现,因此大家不需要自己去实现 Semaphore。
- 简单的 Semaphore 实现
- 使用 Semaphore 来发出信号
- 可计数的 Semaphore
- 有上限的 Semaphore
- 把 Semaphore 当锁来使用
简单的 Semaphore 实现
下面是一个信号量的简单实现:
public class Semaphore {
private boolean signal = false;
public synchronized void take() {
this.signal = true;
this.notify();
}
public synchronized void release() throws InterruptedException{
while(!this.signal) wait();
this.signal = false;
}
}
Take 方法发出一个被存放在 Semaphore 内部的信号,而 Release 方法则等待一个信号,当其接收到信号后,标记位 signal 被清空,然后该方法终止。
使用这个 semaphore 可以避免错失某些信号通知。用 take 方法来代替 notify,release 方法来代替 wait。如果某线程在调用 release 等待之前调用 take 方法,那么调用 release 方法的线程仍然知道 take 方法已经被某个线程调用过了,因为该 Semaphore 内部保存了 take 方法发出的信号。而 wait 和 notify 方法就没有这样的功能。
当用 semaphore 来产生信号时,take 和 release 这两个方法名看起来有点奇怪。这两个名字来源于后面把 semaphore 当做锁的例子,后面会详细介绍这个例子,在该例子中,take 和 release 这两个名字会变得很合理。
使用 Semaphore 来产生信号
下面的例子中,两个线程通过 Semaphore 发出的信号来通知对方
Semaphore semaphore = new Semaphore();
SendingThread sender = new SendingThread(semaphore);
ReceivingThread receiver = new ReceivingThread(semaphore);
receiver.start();
sender.start();
public class SendingThread {
Semaphore semaphore = null;
public SendingThread(Semaphore semaphore){
this.semaphore = semaphore;
}
public void run(){
while(true){
//do something, then signal
this.semaphore.take();
}
}
}
public class RecevingThread {
Semaphore semaphore = null;
public ReceivingThread(Semaphore semaphore){
this.semaphore = semaphore;
}
public void run(){
while(true){
this.semaphore.release();
//receive signal, then do something...
}
}
}
可计数的 Semaphore
上面提到的 Semaphore 的简单实现并没有计算通过调用 take 方法所产生信号的数量。可以把它改造成具有计数功能的 Semaphore。下面是一个可计数的 Semaphore 的简单实现。
public class CountingSemaphore {
private int signals = 0;
public synchronized void take() {
this.signals++;
this.notify();
}
public synchronized void release() throws InterruptedException{
while(this.signals == 0) wait();
this.signals--;
}
}
有上限的 Semaphore
上面的 CountingSemaphore 并没有限制信号的数量。下面的代码将 CountingSemaphore 改造成一个信号数量有上限的 BoundedSemaphore。
public class BoundedSemaphore {
private int signals = 0;
private int bound = 0;
public BoundedSemaphore(int upperBound){
this.bound = upperBound;
}
public synchronized void take() throws InterruptedException{
while(this.signals == bound) wait();
this.signals++;
this.notify();
}
public synchronized void release() throws InterruptedException{
while(this.signals == 0) wait();
this.signals--;
this.notify();
}
}
在 BoundedSemaphore 中,当已经产生的信号数量达到了上限,take 方法将阻塞新的信号产生请求,直到某个线程调用 release 方法后,被阻塞于 take 方法的线程才能传递自己的信号。
把 Semaphore 当锁来使用
当信号量的数量上限是 1 时,Semaphore 可以被当做锁来使用。通过 take 和 release 方法来保护关键区域。请看下面的例子:
BoundedSemaphore semaphore = new BoundedSemaphore(1);
...
semaphore.take();
try{
//critical section
} finally {
semaphore.release();
}
在前面的例子中,Semaphore 被用来在多个线程之间传递信号,这种情况下,take 和 release 分别被不同的线程调用。但是在锁这个例子中,take 和 release 方法将被同一线程调用,因为只允许一个线程来获取信号(允许进入关键区域的信号),其它调用 take 方法获取信号的线程将被阻塞,知道第一个调用 take 方法的线程调用 release 方法来释放信号。对 release 方法的调用永远不会被阻塞,这是因为任何一个线程都是先调用 take 方法,然后再调用 release。
通过有上限的 Semaphore 可以限制进入某代码块的线程数量。设想一下,在上面的例子中,如果 BoundedSemaphore 上限设为 5 将会发生什么?意味着允许 5 个线程同时访问关键区域,但是你必须保证,这个 5 个线程不会互相冲突。否则你的应用程序将不能正常运行。
必须注意,release 方法应当在 finally 块中被执行。这样可以保在关键区域的代码抛出异常的情况下,信号也一定会被释放。
java多线程-信号量的更多相关文章
- java多线程--信号量Semaphore的使用
Semaphore可以控制某个共享资源可被同时访问的次数,即可以维护当前访问某一共享资源的线程个数,并提供了同步机制.例如控制某一个文件允许的并发访问的数量. 例如网吧里有100台机器,那么最多只能提 ...
- Java多线程信号量同步类CountDownLatch与Semaphore
信号量同步是指在不同线程之间,通过传递同步信号量来协调线程执行的先后次序.CountDownLatch是基于时间维度的Semaphore则是基于信号维度的. 1:基于执行时间的同步类CountDown ...
- Java多线程系列--“JUC锁”11之 Semaphore信号量的原理和示例
概要 本章,我们对JUC包中的信号量Semaphore进行学习.内容包括:Semaphore简介Semaphore数据结构Semaphore源码分析(基于JDK1.7.0_40)Semaphore示例 ...
- Java多线程并发工具类-信号量Semaphore对象讲解
Java多线程并发工具类-Semaphore对象讲解 通过前面的学习,我们已经知道了Java多线程并发场景中使用比较多的两个工具类:做加法的CycliBarrier对象以及做减法的CountDownL ...
- Java多线程的信号量
Java的信号量主要的作用是控制线程对资源的访问例如我一个线程池里面有100个线程等待执行,但是我允许最多同时运行5个线程,这5个线程只有其中一个线程执行完毕后,在线程池中等待的线程才能进入开始执行, ...
- 40个Java多线程问题总结
前言 Java多线程分类中写了21篇多线程的文章,21篇文章的内容很多,个人认为,学习,内容越多.越杂的知识,越需要进行深刻的总结,这样才能记忆深刻,将知识变成自己的.这篇文章主要是对多线程的问题进行 ...
- java从基础知识(十)java多线程(上)
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元.另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点 ...
- Java多线程系列--“JUC锁”01之 框架
本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--“JUC锁”01之 框架02. Java多线程系列--“JUC锁”02之 互斥锁Reentrant ...
- Java多线程系列目录(共43篇)
最近,在研究Java多线程的内容目录,将其内容逐步整理并发布. (一) 基础篇 01. Java多线程系列--“基础篇”01之 基本概念 02. Java多线程系列--“基础篇”02之 常用的实现多线 ...
随机推荐
- PHP的静态和接口
静态普通成员普通成员属于对象//静态成员//静态成员属于类//static 关键字 变成静态成员/*class ren { public $name; public static $zho ...
- .Net中List<T> 泛型转成DataTable、DataSet
在开发过程过程中有时候需要将List<T>泛型转换成DataTable.DataSet,可以利用反射机制将DataTable的字段与自定义类型的公开属性互相赋值. 1.List<T& ...
- HTTP学习一:HTTP基础知识
1 HTTP介绍 HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议. 它的发展是万维网协会(World Wid ...
- Hello Blog
转眼之间,工作已经快五年了. 五年走的时候不觉得,当真正过来了,一回头,才真正体会到什么叫时间匆匆. 做了五年的技术,算是多有波折.想一想,做技术真的挺需要耐得住寂寞的,毕竟花花世界,压力太大,诱惑太 ...
- SSISDB1:使用SSISDB管理SSIS Projects
使用Project Deployment Model,将SSIS Project部署到Integration Services Catalog之后,SSISDB负责管理SSIS Project.在SS ...
- SVN-让项目不包括Bin和Obj
方案一: 方案二: 方法三: 添加自定义文件夹或者文件的过滤 eg:.svn .git .vs obj bin *.o *.lo *.la *.al .libs *.so *.so.[0-9]* * ...
- Sql Server系列:运算符和表达式
运算符的一些符号,他们能够用于执行算术运算.字符串连接.赋值以及在字段.常量和变量之间进行比较.在SQL Server 2012中,运算符主要由以下6大类:算术运算符.赋值运算符.比较运算符.逻辑运算 ...
- Entity Framework Code First实体关联数据加载
在项目过程中,两个实体数据之间在往往并非完全独立的,而是存在一定的关联关系,如一对一.一对多及多对多等关联.存在关联关系的实体,经常根据一个实体的实例来查询获取与之关联的另外实体的实例. Entity ...
- 解决升级Win 10 IP 10122后无法调试UAP应用的方法
可能各位也像老周一样,第一时间升级了Build 10122,但不知道大家有没有发现,当你升级后,写一个UAP应用,要调试运行时,就会出错,错误如下: DEP0730 : 注册应用程序失败,因为目标计算 ...
- java自定义类加载器
前言 java反射,最常用的Class.forName()方法.做毕设的时候,接收到代码字符串,通过 JavaCompiler将代码字符串生成A.class文件(存放在classpath下,也就是ec ...