以下内容转自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并发性和多线程-信号量的更多相关文章

  1. Java并发性和多线程介绍

    java并发性和多线程介绍: 单个程序内运行多个线程,多任务并发运行 多线程优点: 高效运行,多组件并行.读->操作->写: 程序设计的简单性,遇到多问题,多开线程就好: 快速响应,异步式 ...

  2. java 并发性和多线程 -- 读感 (一 线程的基本概念部分)

    1.目录略览      线程的基本概念:介绍线程的优点,代价,并发编程的模型.如何创建运行java 线程.      线程间通讯的机制:竞态条件与临界区,线程安全和共享资源与不可变性.java内存模型 ...

  3. Java并发性和多线程

    Java并发性和多线程介绍   java并发性和多线程介绍: 单个程序内运行多个线程,多任务并发运行 多线程优点: 高效运行,多组件并行.读->操作->写: 程序设计的简单性,遇到多问题, ...

  4. Java 并发和多线程(一) Java并发性和多线程介绍[转]

    作者:Jakob Jenkov 译者:Simon-SZ  校对:方腾飞 http://tutorials.jenkov.com/java-concurrency/index.html 在过去单CPU时 ...

  5. Java高级教程:Java并发性和多线程

    Java并发性和多线程: (中文,属于人工翻译,高质量):http://ifeve.com/java-concurrency-thread-directory/ (英文):http://tutoria ...

  6. Java 并发性和多线程

    一.介绍 在过去单 CPU 时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程.虽然并不是真正意义上的“同一时间点”,而是多个任务或进程共享一个 ...

  7. 1、Java并发性和多线程-并发性和多线程介绍

    以下内容转自http://ifeve.com/java-concurrency-thread/: 在过去单CPU时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行 ...

  8. 6、Java并发性和多线程-并发性与并行性

    以下内容转自http://tutorials.jenkov.com/java-concurrency/concurrency-vs-parallelism.html(使用谷歌翻译): 术语并发和并行性 ...

  9. 4、Java并发性和多线程-并发编程模型

    以下内容转自http://ifeve.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E6%A8%A1%E5%9E%8B/: 并发系统可以采用多种并发编程模型来实现. ...

随机推荐

  1. 洛谷 P2881 [USACO07MAR]排名的牛Ranking the Cows

    题应该是假的...先不做了 https://www.cnblogs.com/Blue233333/p/7249057.html 比如输入5 0,答案是10,但可以比较8次就出来.就是在一个已知有序数列 ...

  2. Manacher HDOJ 3068 最长回文

    题目传送门 关于求解最长回文子串,有dp做法,也有同样n^2的但只用O(1)的空间,还有KMP,后缀数组?? int main(void) { ) == ) { ); memset (dp, fals ...

  3. SQL数据库,增加查询修改以及防sql写入攻击

    SQL添加信息 SQL查询信息 SQL修改信息 SQL语句写入攻击: 普通语句添加信息 sql写入语句攻击: 解决方法:分开传送语句与参数关键:@

  4. NodeJs学习记录(五)初学阶段关于ejs和路由

    1.因为只是用了一点皮毛,所以使用起来感觉基本和jsp无异, 逻辑代码块使用  <%  if() {} else  %> , 输出参数值使用 <%=title  %>, 有一个 ...

  5. 神奇的Object.defineProperty

    vue.js和avalon.js 都是通过它实现双向绑定的. 对象是由多个名/值对组成的无序的集合.对象中每个属性对应任意类型的值.定义对象可以使用构造函数或字面量的形式: var obj={}; o ...

  6. opencv3+python+pycharm报错问题(cmd命令正常)

    2018-03-0223:58:59 首先在你已成功安装python的情况下运行cmd命令,下载安装opencv插件 如果在命令行可以使用 import cv2 但是在IDE上面只输入import c ...

  7. git reset作用

    git reset: 1. 文件从暂存区回退到工作区,撤销add 2. 版本回退  一:文件从暂存区回退到工作区,撤销add 如果想取消某个add的文件,可以使用该命令来进行撤销操作 撤消add:gi ...

  8. Angular——自定义过滤器

    基本介绍 除了使用AngularJS内建过滤器外,还可以根业务需要自定义过滤器,通过模块对象实例提供的filter方法自定义过滤器. 基本使用 (1)input是将绑定的数据以参数的形式传入 (2)i ...

  9. 3星|《未来公司》:Uber简史

    未来公司(卡兰尼克和他的Uber帝国)(精) 从Uber创始人卡兰尼克的角度讲的Uber简史,截止到2017年.书中有不少Uber的负面新闻,比国内的同类书要好. 基本是流水账.想了解这家公司的历史, ...

  10. Computed Properties vs Property Requirements - protocol

    In addition to stored properties, classes, structures, and enumerations can define computed properti ...