24、Java并发性和多线程-信号量
以下内容转自http://ifeve.com/semaphore/:
Semaphore(信号量) 是一个线程同步结构,用于在线程间传递信号,以避免出现信号丢失(译者注:下文会具体介绍),或者像锁一样用于保护一个关键区域。自从5.0开始,jdk在java.util.concurrent包里提供了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块中被执行。这样可以保在关键区域的代码抛出异常的情况下,信号也一定会被释放。
24、Java并发性和多线程-信号量的更多相关文章
- Java并发性和多线程介绍
java并发性和多线程介绍: 单个程序内运行多个线程,多任务并发运行 多线程优点: 高效运行,多组件并行.读->操作->写: 程序设计的简单性,遇到多问题,多开线程就好: 快速响应,异步式 ...
- java 并发性和多线程 -- 读感 (一 线程的基本概念部分)
1.目录略览 线程的基本概念:介绍线程的优点,代价,并发编程的模型.如何创建运行java 线程. 线程间通讯的机制:竞态条件与临界区,线程安全和共享资源与不可变性.java内存模型 ...
- Java并发性和多线程
Java并发性和多线程介绍 java并发性和多线程介绍: 单个程序内运行多个线程,多任务并发运行 多线程优点: 高效运行,多组件并行.读->操作->写: 程序设计的简单性,遇到多问题, ...
- Java 并发和多线程(一) Java并发性和多线程介绍[转]
作者:Jakob Jenkov 译者:Simon-SZ 校对:方腾飞 http://tutorials.jenkov.com/java-concurrency/index.html 在过去单CPU时 ...
- Java高级教程:Java并发性和多线程
Java并发性和多线程: (中文,属于人工翻译,高质量):http://ifeve.com/java-concurrency-thread-directory/ (英文):http://tutoria ...
- Java 并发性和多线程
一.介绍 在过去单 CPU 时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程.虽然并不是真正意义上的“同一时间点”,而是多个任务或进程共享一个 ...
- 1、Java并发性和多线程-并发性和多线程介绍
以下内容转自http://ifeve.com/java-concurrency-thread/: 在过去单CPU时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行 ...
- 6、Java并发性和多线程-并发性与并行性
以下内容转自http://tutorials.jenkov.com/java-concurrency/concurrency-vs-parallelism.html(使用谷歌翻译): 术语并发和并行性 ...
- 4、Java并发性和多线程-并发编程模型
以下内容转自http://ifeve.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E6%A8%A1%E5%9E%8B/: 并发系统可以采用多种并发编程模型来实现. ...
随机推荐
- ACM_天涯若比邻(最小与最大相邻素数)
天涯若比邻 Time Limit: 2000/1000ms (Java/Others) Problem Description: 一心想搞ACM的小G最近迷上了数论,特别对于跟“素数”相关的问题特别有 ...
- 锚点、target="page1"、浮标回到顶部(该点未实现,能力不足)
<html> <head> <meta charset="utf-8"> <title>链接</title> <! ...
- 深度优先搜索DFS和广度优先搜索BFS简单解析
转自:https://www.cnblogs.com/FZfangzheng/p/8529132.html 深度优先搜索DFS和广度优先搜索BFS简单解析 与树的遍历类似,图的遍历要求从某一点出发,每 ...
- Java图片上查找图片算法
之前用按键精灵写过一些游戏辅助,里面有个函数叫FindPic,就是在屏幕范围查找给定的一张图片,返回查找到的坐标位置. 现在,Java来实现这个函数类似的功能. 算法描述: 屏幕截图,得到图A,(查找 ...
- java 8 stream使用
使用stream代替循环的方案 1.定义一个Article类包括标题.作者.标签 private class Article { private final String title; private ...
- STL容器的排序
STL容器的排序,支持随机访问的容器vector,deque,string没有sort成员,可调用std::sort排序:list排序调用自带的list::sort. 下面是std::sort函数,有 ...
- Java基础(四)--接口和抽象类
接口和抽象类能够体现OOP的抽象,而接口和抽象类也是日常开发中经常用到的 抽象方法: 抽象方法就是被abstract修饰的方法,只有声明,没有实现,也就是没有方法体 public abstract v ...
- 汇编学习pushl, popl
- JPA 与 JDBC 的区别和基本用法
JPA 概念 JPA(Java Persistence API)用于对象持久化的 API,是 Java EE 5.0 平台标准的 ORM 规范,使得应用程序以统一的方式访问持久层. 与 JDBC 的对 ...
- The King’s Ups and Downs(HDU 4489,动态规划递推,组合数,国王的游戏)
题意: 给一个数字n,让1到n的所有数都以波浪形排序,即任意两个相邻的数都是一高一低或者一低一高 比如:1324 4231,再比如4213就是错的,因为4高,2低,接下来1就应该比2高,但是它没有 ...