1. 概述

Semaphore(信号)  并不存在真正的许可 只是维护一个计数器, 通常用来限定进入一些资源的线程数

 accquire()  方法获取许可 成功则计数器值-1 没有则阻塞直到一个可用的许可(即计数器>0)

release() 方法 潜在的释放了申请人(通过给计数器值+1)

2. 示例一(单独测试信号量增减  availabelPermits对超出数量的线程的阻塞)

  1. package com.rocky.semaphore;
  2.  
  3. import java.util.concurrent.ExecutorService;
  4. import java.util.concurrent.Executors;
  5. import java.util.concurrent.Semaphore;
  6.  
  7. public class SemaphoreTest {
  8.  
  9. public static void main(String[] args) {
  10. Semaphore semaphore = new Semaphore(5, false);//no fair 并行最大为5,阻塞后来的
  11. ExecutorService service = Executors.newCachedThreadPool();
  12. for(int i=0; i<10; i++){
  13. service.execute(new Worker(semaphore));
  14. }
  15. service.shutdown();
  16. }
  17.  
  18. }
  19.  
  20. class Worker implements Runnable{
  21.  
  22. private Semaphore semaphore;
  23. Worker(Semaphore semaphore){
  24. this.semaphore = semaphore;
  25. }
  26. @Override
  27. public void run() {
  28. try {
  29. semaphore.acquire();//获取许可
  30. try {
  31. System.out.println(Thread.currentThread().getName()+" accessing...");
  32. Thread.sleep((long) (Math.random()*3000));
  33. } finally{
  34. semaphore.release();//释放许可
  35. System.out.println(Thread.currentThread().getName()+" leaving...");
  36. }
  37. } catch (InterruptedException e) {
  38. e.printStackTrace();
  39. }
  40. }}

说明:   默认是非公平的 进来一个线程获取许可, 则state减1,直到值为0 以下是源码片段

  1. final int nonfairTryAcquireShared(int acquires) {//acquires值为1
  2. for (;;) {
  3. int available = getState();//当前state值
  4. int remaining = available - acquires;
  5. if (remaining < 0 ||
  6. compareAndSetState(available, remaining))//remaining>0 则CAS修改state 成功获取许可
  7. return remaining;
  8. }
  9. }
  10.  
  11.   //remainimg<0 返回后,执行下面方法
  12. private void doAcquireSharedInterruptibly(int arg)
  13. throws InterruptedException {
  14. final Node node = addWaiter(Node.SHARED);//创建共享型节点加入等待队列 队列为空则仿制头结点并建立联系
  15. try {
  16. for (;;) {
  17. final Node p = node.predecessor();
  18. if (p == head) {
  19. int r = tryAcquireShared(arg);//再次尝试获取许可
  20. if (r >= 0) {//成功获取许可
  21. setHeadAndPropagate(node, r);
  22. p.next = null; // help GC
  23. return;
  24. }
  25. }
  26. if (shouldParkAfterFailedAcquire(p, node) &&
  27. parkAndCheckInterrupt())
  28. break;
  29. }
  30. } catch (RuntimeException ex) {
  31. cancelAcquire(node);
  32. throw ex;
  33. }
  34. // Arrive here only if interrupted
  35. cancelAcquire(node);
  36. throw new InterruptedException();
  37. }

3. 示例二(一个生产者与一个消费者 两组信号量 此消彼长 为0阻塞)

  1. package com.rocky.semaphore;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.Executors;
  7. import java.util.concurrent.Semaphore;
  8.  
  9. public class ProducerCustomRealizeWithSemaphore {
  10.  
  11. public static void main(String[] args) {
  12. SemaphoreBuffer semaphoreBuffer = new SemaphoreBuffer();
  13. Producer producer = new Producer(semaphoreBuffer);
  14. Customer customer = new Customer(semaphoreBuffer);
  15. ExecutorService service = Executors.newCachedThreadPool();
  16. service.execute(customer);
  17. service.execute(producer);
  18. service.shutdown();
  19. }
  20.  
  21. }
  22.  
  23. class SemaphoreBuffer{
  24. List<Integer> list = new ArrayList<Integer>();
  25. Semaphore producerSemaphore = new Semaphore(1);// 允许并行的线程数为1
  26. Semaphore customerSemaphore = new Semaphore(0);// 0即state的初始值 则一开始消费就阻塞了 见上例说明中remaining<0
  27.  
  28. public void put(int num){
  29. try {
  30. producerSemaphore.acquire();
  31. try {
  32. list.add(num);
  33. } finally{
  34. customerSemaphore.release();
  35. }
  36. } catch (InterruptedException e) {
  37. e.printStackTrace();
  38. }
  39. }
  40.  
  41. public int get(){
  42. try {
  43. customerSemaphore.acquire();
  44. try{
  45. return list.remove(0);
  46. }finally{
  47. producerSemaphore.release();
  48. }
  49. } catch (InterruptedException e) {
  50. e.printStackTrace();
  51. }
  52. return 0;
  53. }
  54.  
  55. }
  56.  
  57. class Customer implements Runnable{
  58. private SemaphoreBuffer buffer;
  59. Customer(SemaphoreBuffer buffer){
  60. this.buffer = buffer;
  61. }
  62. @Override
  63. public void run() {
  64. while(!Thread.interrupted()){
  65. int num = buffer.get();
  66. System.out.println("Customer get the num "+num);
  67. try {
  68. Thread.sleep(2000);
  69. } catch (InterruptedException e) {
  70. e.printStackTrace();
  71. }
  72. }
  73.  
  74. }
  75. }
  76.  
  77. class Producer implements Runnable{
  78. private SemaphoreBuffer buffer;
  79. Producer(SemaphoreBuffer buffer){
  80. this.buffer = buffer;
  81. }
  82. int c =0;
  83. @Override
  84. public void run() {
  85.  
  86. while(!Thread.interrupted()){
  87. buffer.put(c);
  88. System.out.println("Producer put the num "+c);
  89. c++;
  90. try {
  91. Thread.sleep(2000);
  92. } catch (InterruptedException e) {
  93. e.printStackTrace();
  94. }
  95. }
  96. }
  97.  
  98. }

4. 示例三(多个生产者与多个消费者 运用阻塞队列  线程安全 )

  1. package com.rocky.semaphore;
  2.  
  3. import java.util.concurrent.BlockingQueue;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. import java.util.concurrent.LinkedBlockingDeque;
  7. import java.util.concurrent.LinkedBlockingQueue;
  8. import java.util.concurrent.Semaphore;
  9. import java.util.concurrent.atomic.AtomicInteger;
  10.  
  11. public class ProducerCustomRealizeWithSemaphoreLinkedBlockingQueue {
  12.  
  13. static AtomicInteger c = new AtomicInteger(1);
  14. public static void main(String[] args) {
  15. ExecutorService service = Executors.newCachedThreadPool();
  16. CakeStand stand = new CakeStand();
  17. service.execute(new CakeProducer(stand, "producer1", c));
  18. service.execute(new CakeProducer(stand, "producer2", c));
  19. service.execute(new CakeProducer(stand, "producer3", c));
  20. service.execute(new CakeCustomer(stand, "customer1"));
  21. service.execute(new CakeCustomer(stand, "customer2"));
  22. }
  23. }
  24.  
  25. class Cake{
  26. private String name;
  27. Cake(String name){
  28. this.name = name;
  29. }
  30. public String toString(){
  31. return name;
  32. }
  33. }
  34.  
  35. class CakeStand{
  36. BlockingQueue<Cake> queue = new LinkedBlockingQueue<Cake>(15);
  37. Semaphore notFull = new Semaphore(10);//生产信号量
  38. Semaphore notEmpty = new Semaphore(0);//消费信号量
  39. public void put(Cake cake){
  40. try {
  41. notFull.acquire();
  42. try{
  43. queue.put(cake);
  44. }finally{
  45. notEmpty.release();
  46. }
  47. } catch (InterruptedException e) {
  48. e.printStackTrace();
  49. }
  50.  
  51. }
  52.  
  53. public Cake take(){
  54. try {
  55. notEmpty.acquire();
  56. try{
  57. Cake cake = queue.take();
  58. return cake;
  59. }finally{
  60. notFull.release();
  61. }
  62. } catch (InterruptedException e) {
  63. e.printStackTrace();
  64.  
  65. }
  66. return null;
  67. }
  68. }
  69.  
  70. class CakeProducer implements Runnable{
  71.  
  72. private CakeStand stand;
  73. private String name;
  74. private AtomicInteger c;
  75. public CakeProducer(CakeStand stand, String name, AtomicInteger c) {
  76. this.stand = stand;
  77. this.name = name;
  78. this.c = c;
  79. }
  80. @Override
  81. public void run() {
  82. while(!Thread.interrupted()){
  83. String str = "cake-"+c.getAndIncrement();
  84. System.out.println("生产:"+name+"-"+str);
  85. stand.put(new Cake(str));
  86. try {
  87. Thread.sleep(1500);
  88. } catch (InterruptedException e) {
  89. e.printStackTrace();
  90. }
  91. }
  92.  
  93. }
  94. }
  95. class CakeCustomer implements Runnable{
  96.  
  97. private CakeStand stand;
  98. private String name;
  99. public CakeCustomer(CakeStand stand, String name){
  100. this.stand = stand;
  101. this.name = name;
  102.  
  103. }
  104.  
  105. @Override
  106. public void run() {
  107. while(!Thread.interrupted()){
  108. Cake cake = stand.take();
  109. System.err.println("消费:"+name+"-"+cake.toString());
  110. try {
  111. Thread.sleep(1000);
  112. } catch (InterruptedException e) {
  113. e.printStackTrace();
  114. }
  115. }
  116. }
  117. }

说明1): 传统的消费者 生产者使用wait/notify模式等待和相互唤醒, Semaphore通过信号量的值控制运行(>0)和阻塞(<=0),

两组信号量可以使两组角色彼此唤醒,使用阻塞队列可以确保线程安全。

2) 可以额外创建一个信号量Semaphore mutex = new Semaphore(1); 在获取本组信号量之后再获取metex信号量可以实现互斥锁效果

java.util.concurrent.Semaphore 使用的更多相关文章

  1. 161207、高并发:java.util.concurrent.Semaphore实现字符串池及其常用方法介绍

    实现字符串池: StrPool.java import java.util.ArrayList; import java.util.List; import java.util.concurrent. ...

  2. 聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore

    前几篇分析了一下AQS的原理和实现.这篇拿Semaphore信号量做样例看看AQS实际是怎样使用的. Semaphore表示了一种能够同一时候有多个线程进入临界区的同步器,它维护了一个状态表示可用的票 ...

  3. [转载] java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger

    转载自http://janeky.iteye.com/blog/770393 ------------------------------------------------------------- ...

  4. Java 并发工具包 java.util.concurrent 用户指南

    1. java.util.concurrent - Java 并发工具包 Java 5 添加了一个新的包到 Java 平台,java.util.concurrent 包.这个包包含有一系列能够让 Ja ...

  5. Java并发编程-并发工具包(java.util.concurrent)使用指南(全)

    1. java.util.concurrent - Java 并发工具包 Java 5 添加了一个新的包到 Java 平台,java.util.concurrent 包.这个包包含有一系列能够让 Ja ...

  6. java.util.concurrent包API学习笔记

    newFixedThreadPool 创建一个固定大小的线程池. shutdown():用于关闭启动线程,如果不调用该语句,jvm不会关闭. awaitTermination():用于等待子线程结束, ...

  7. java.util.concurrent 多线程框架

    http://daoger.iteye.com/blog/142485 JDK5中的一个亮点就是将Doug Lea的并发库引入到Java标准库中.Doug Lea确实是一个牛人,能教书,能出书,能编码 ...

  8. Java_并发工具包 java.util.concurrent 用户指南(转)

    译序 本指南根据 Jakob Jenkov 最新博客翻译,请随时关注博客更新:http://tutorials.jenkov.com/java-util-concurrent/index.html.本 ...

  9. 013-并发编程-java.util.concurrent.locks之-AbstractQueuedSynchronizer-用于构建锁和同步容器的框架、独占锁与共享锁的获取与释放

    一.概述 AbstractQueuedSynchronizer (简称AQS),位于java.util.concurrent.locks.AbstractQueuedSynchronizer包下, A ...

随机推荐

  1. php-elasticsearch scroll分页详解

    背景 ps:首先我们在一个索引里面写入一万条以上的数据.作为数据源 现在我想看到第一万零一条数据,首先第一想法是,from 10000 size 1 ,这样做会包下面错误.显然是不成立的.此时便会用到 ...

  2. Web开发模式

    原文链接 开发模式的介绍(完善版) 在Web开发模式中,有两个主要的开发结构,称为模式一(Mode I)和模式二(Mode II). 首先我们来理清一些概念吧: DAO(Data Access Obj ...

  3. tomcat增加运行内存

    内容为: set JAVA_OPTS=%JAVA_OPTS% -server -Xms2048m -Xmx2048m -XX:PermSize=212M -XX:MaxPermSize=512m 在m ...

  4. C#集合之位数组

    如果需要处理的数字有许多位,就可以使用BitArray类和BitVector32结构.BitArray类位于System.Collection,BitVector32结构位于System.Collec ...

  5. eAccelerator 配置参数详解

    eAccelerator配置参数如下: [eaccelerator]extension=eaccelerator.soeaccelerator.shm_size="64"eacce ...

  6. Windows USB 编程

    GUID #include <initguid.h> // For DEFINE_GUID // Device Interface GUID.DEFINE_GUID(GUID_DEVINT ...

  7. Git版本回退和撤销修改

    版本回退: 在实际工作中,我们会不断对文件进行修改,然后不断提交修改到版本库里,一旦你把文件改乱了,或者误删了文件,还可以从最近的一个commit恢复,然后继续工作,而不是把几个月的工作成果全部丢失. ...

  8. CentOS下安装官方RPM包的MySQL后找不到my.cnf

    PS:昨天一同事问我说他用MySQL 5.5官方的rpm包安装了,但是在/etc/下面没有my.cnf配置文件.官方rpm包安装的mysql默认确实是没有/etc/my.cnf. 为什么没有这个文件而 ...

  9. RequireJs学习笔记之data-main Entry Point

    You will typically use a data-main script to set configuration options and then load the first appli ...

  10. Log4J 配置文件模板及代码说明

    相对而言,这个日志系统的配置就没那么随意了,而且有些功能用起来也不是那么爽,譬如动态读取配置文件.不过鉴于使用这个日志的系统还是很多,所以也写一个demo贴出来,风格跟log4j2一样,配置的说明全在 ...