前言

  JDK中为了处理线程之间的同步问题,除了提供锁机制之外,还提供了几个非常有用的并发工具类:CountDownLatch、CyclicBarrier、Semphore、Exchanger、Phaser;

  CountDownLatch、CyclicBarrier、Semphore、Phaser 这四个工具类提供一种并发流程的控制手段;而Exchanger工具类则提供了在线程之间交换数据的一种手段。

简介

  Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。很多年以来,我都觉得从字面上很难理解Semaphore所表达的含义,只能把它比作是控制流量的红绿灯,比如XX马路要限制流量,只允许同时有一百辆车在这条路上行使,其他的都必须在路口等待,所以前一百辆车会看到绿灯,可以开进这条马路,后面的车会看到红灯,不能驶入XX马路,但是如果前一百辆中有五辆车已经离开了XX马路,那么后面就允许有5辆车驶入马路,这个例子里说的车就是线程,驶入马路就表示线程在执行,离开马路就表示线程执行完成,看见红灯就表示线程被阻塞,不能执行。

应用场景

  Semaphore可以用于做流量控制,特别公用资源有限的应用场景,比如数据库连接。假如有一个需求,要读取几万个文件的数据,因为都是IO密集型任务,我们可以启动几十个线程并发的读取,但是如果读到内存后,还需要存储到数据库中,而数据库的连接数只有10个,这时我们必须控制只有十个线程同时获取数据库连接保存数据,否则会报错无法获取数据库连接。这个时候,我们就可以使用Semaphore来做流控,代码如下:

  1. public class SemaphoreTest {
  2. private static final int THREAD_COUNT = 30;
  3. private static ExecutorService threadPool = Executors
  4. .newFixedThreadPool(THREAD_COUNT);
  5. private static Semaphore s = new Semaphore(10);
  6. public static void main(String[] args) {
  7. for (int i = 0; i < THREAD_COUNT; i++) {
  8. threadPool.execute(new Runnable() {
  9. @Override
  10. public void run() {
  11. try {
  12. s.acquire();
  13. System.out.println("save data");
  14. s.release();
  15. } catch (InterruptedException e) {
  16. }
  17. }
  18. });
  19. }
  20. threadPool.shutdown();
  21. }
  22. }

  在代码中,虽然有30个线程在执行,但是只允许10个并发的执行。Semaphore的构造方法Semaphore(int permits) 接受一个整型的数字,表示可用的许可证数量。Semaphore(10)表示允许10个线程获取许可证,也就是最大并发数是10。Semaphore的用法也很简单,首先线程使用Semaphore的acquire()获取一个许可证,使用完之后调用release()归还许可证。还可以用tryAcquire()方法尝试获取许可证。

Semphore的方法摘要

1、获取许可

  API中提供了多种的方式获取锁:

  • 可以获取一个、多个许可;
  • 提供阻塞、非阻塞、超时的方式获取许可;
  • 除了可中断、还提供一个非中断的方式获取锁;

public void acquire() throws InterruptedException

从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。

public void acquire(int permits) throws InterruptedException

获取多个许可。从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞,或者线程已被中断。

public void acquireUninterruptibly()

从此信号量中获取许可,在有可用的许可前将其阻塞。不可中断。

public void acquireUninterruptibly(int permits)

获取多个许可。从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞。不可中断。

public boolean tryAcquire()

仅在调用时此信号量存在一个可用许可,才从信号量获取许可。非阻塞的方式尝试获取许可。

public boolean tryAcquire(int permits)

仅在调用时此信号量中有给定数目的许可时,才从此信号量中获取这些许可。

public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException

如果在给定的等待时间内此信号量有可用的所有许可,并且当前线程未被中断,则从此信号量获取给定数目的许可。超时等待获取许可

public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException

如果在给定的等待时间内,此信号量有可用的许可并且当前线程未被中断,则从此信号量获取一个许可。

2、许可的释放

public void release( ):

释放一个许可,将其返回给信号量。

public void release(int permits)

释放给定数目的许可,将其返回到信号量。

3、提供的监控方法

public int availablePermits( )

返回此信号量中当前可用的许可数

public int drainPermits()

获取并返回立即可用的所有许可

public final int getQueueLength()

返回正在等待获取的线程的估计数目。该值仅是估计的数字,因为在此方法遍历内部数据结构的同时,线程的数目可能动态地变化。此方法用于监视系统状态,不用于同步控制。

public final boolean hasQueuedThreads()

查询是否有线程正在等待获取。

public boolean isFair()

如果此信号量的公平设置为 true,则返回 true。

protected 方法:

protected Collection getQueuedThreads( )

返回一个 collection,包含可能等待获取的线程。因为在构造此结果的同时实际的线程 set 可能动态地变化,所以返回的 collection 仅是尽力的估计值。所返回 collection 中的元素没有特定的顺序。

protected void reducePermits(int reduction)

根据指定的缩减量减小可用许可的数目。此方法在使用信号量来跟踪那些变为不可用资源的子类中很有用

@ Example 获取、释放多个许可

  1. try {
  2. Semaphore semaphore = new Semaphore(5);
  3. //获取一个许可
  4. semaphore.acquire();
  5. //一次性获取4个许可
  6. semaphore.acquire(4);
  7. System.out.println("Semaphore 剩下的许可数量:"+semaphore.availablePermits());
  8. //一次性释放5个许可
  9. semaphore.release(5);
  10. System.out.println("Semaphore 剩下的许可数量:"+semaphore.availablePermits());
  11. //再释放5个许可
  12. semaphore.release();
  13. semaphore.release();
  14. semaphore.release(3);
  15. System.out.println("Semaphore 剩下的许可数量:"+semaphore.availablePermits());
  16. } catch (InterruptedException e) {
  17. e.printStackTrace();

运行结果:

Semaphore 剩下的许可数量:0

Semaphore 剩下的许可数量:5

Semaphore 剩下的许可数量:10

   从上面的运行结果可以看出,构造方法的 new Semaphore(5)中参数5并不是最终的许可数量,可以通过release()方法增加许可数量。

文献:

  • 《java并发编程的艺术》

并发工具类(三)控制并发线程的数量 Semphore的更多相关文章

  1. 并发工具类(四)线程间的交换数据 Exchanger

    前言   JDK中为了处理线程之间的同步问题,除了提供锁机制之外,还提供了几个非常有用的并发工具类:CountDownLatch.CyclicBarrier.Semphore.Exchanger.Ph ...

  2. 【Java并发工具类】Java并发容器

    前言 Java并发包有很大一部分都是关于并发容器的.Java在5.0版本之前线程安全的容器称之为同步容器.同步容器实现线程安全的方式:是将每个公有方法都使用synchronized修饰,保证每次只有一 ...

  3. Java线程的并发工具类

    Java线程的并发工具类. 一.fork/join 1. Fork-Join原理 在必要的情况下,将一个大任务,拆分(fork)成若干个小任务,然后再将一个个小任务的结果进行汇总(join). 适用场 ...

  4. 【重学Java】多线程进阶(线程池、原子性、并发工具类)

    线程池 线程状态介绍 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.线程对象在不同的时期有不同的状态.那么Java中的线程存在哪几种状态呢?Java中的线程 状态被定 ...

  5. Java并发编程-并发工具类及线程池

    JUC中提供了几个比较常用的并发工具类,比如CountDownLatch.CyclicBarrier.Semaphore. CountDownLatch: countdownlatch是一个同步工具类 ...

  6. java线程并发工具类CyclicBarrier、CountDownLatch及Semaphore

    一.CyclicBarrier   (原文链接:http://www.studyshare.cn/blog-front/blog/index ) 1.定义 CyclicBarrier是线程并发工具类之 ...

  7. Java并发编程系列-(2) 线程的并发工具类

    2.线程的并发工具类 2.1 Fork-Join JDK 7中引入了fork-join框架,专门来解决计算密集型的任务.可以将一个大任务,拆分成若干个小任务,如下图所示: Fork-Join框架利用了 ...

  8. 线程并发工具类之CountDownLatch的使用及原理分析

    原文链接:http://www.studyshare.cn/blog/details/1149/1 java开发工具下载地址及安装教程大全,点这里.更多技术文章,在这里. 一.定义 CountDown ...

  9. 并发工具类:CountDownLatch、CyclicBarrier、Semaphore

    在多线程的场景下,有些并发流程需要人为来控制,在JDK的并发包里提供了几个并发工具类:CountDownLatch.CyclicBarrier.Semaphore. 一.CountDownLatch ...

随机推荐

  1. ACM 常见词汇

    rectangular 美:  [rek'tæŋɡjələr] 英:  [rek'tæŋɡjʊlə(r)] adj. 矩形的:成直角的   grid 美:  [ɡrɪd] 英:  [ɡrɪd] n. ...

  2. 2018CCPC女生赛(树上莫队)

    签到题这里久懒得写了. B - 缺失的数据范围 Total Submission(s): 2602    Accepted Submission(s): 559 题意:求最大的N,满足N^a*[log ...

  3. L3-017 森森快递 (30 分)

    森森开了一家快递公司,叫森森快递.因为公司刚刚开张,所以业务路线很简单,可以认为是一条直线上的N个城市,这些城市从左到右依次从0到(编号.由于道路限制,第i号城市(,)与第(号城市中间往返的运输货物重 ...

  4. Mac无法上网

    今天mac突然无法上网了, 家里的大部分设备, 都出现了重启后无法上网的问题, 猜测可能是dns有问题了. 于是乎, 在mac中添加了如下DNS 114.114.114.114 8.8.8.8 1.1 ...

  5. 相邻行列相互影响的状态类问题(类似状压dp的搜索)(POJ3279)

    POJ3279http://poj.org/problem?id=3279 题意:黑白的板,每次选择一个十字形翻转(十字板内黑白互换,若是边界则不管),求最小将原图变为全白的策略. 这是一道对于每个格 ...

  6. ballerina 学习 三十 扩展开发(一)

    ballerina 主要是分为两大类 基于ballerina 语言开发的,一般是客户端的connector 使用java语言开发的(类似的基于jvm的都可以),一般是注解以及进行构件生成 baller ...

  7. vulcanjs 包类型

    npm 添加在pacakge.json 文件中的 meteor core 包 由meteor 框架提供的 meteor remote 包 从包服务器加载的,使用username:package 格式组 ...

  8. 作为一名IT从业者,你在工作和学习中,遇到哪些问题

    版权声明:襄阳雷哥的版权声明 https://blog.csdn.net/FansUnion/article/details/28448975 大家都是IT从业者,遇到的问题多少与类似. 假设能把这些 ...

  9. sprintf拼接字符串的问题

    ] = {}; char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', ...

  10. JS enter事件及数据不完整阻止下一步操作

    阻止下一步操作: 1.return false;  2.e.preventDefault(); 但IE8不支持 //键盘事件|enter $(function () { document.onkeyd ...