java.util.concurrent.Semaphore 使用
1. 概述
Semaphore(信号) 并不存在真正的许可 只是维护一个计数器, 通常用来限定进入一些资源的线程数
accquire() 方法获取许可 成功则计数器值-1 没有则阻塞直到一个可用的许可(即计数器>0)
release() 方法 潜在的释放了申请人(通过给计数器值+1)
2. 示例一(单独测试信号量增减 availabelPermits对超出数量的线程的阻塞)
- package com.rocky.semaphore;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Semaphore;
- public class SemaphoreTest {
- public static void main(String[] args) {
- Semaphore semaphore = new Semaphore(5, false);//no fair 并行最大为5,阻塞后来的
- ExecutorService service = Executors.newCachedThreadPool();
- for(int i=0; i<10; i++){
- service.execute(new Worker(semaphore));
- }
- service.shutdown();
- }
- }
- class Worker implements Runnable{
- private Semaphore semaphore;
- Worker(Semaphore semaphore){
- this.semaphore = semaphore;
- }
- @Override
- public void run() {
- try {
- semaphore.acquire();//获取许可
- try {
- System.out.println(Thread.currentThread().getName()+" accessing...");
- Thread.sleep((long) (Math.random()*3000));
- } finally{
- semaphore.release();//释放许可
- System.out.println(Thread.currentThread().getName()+" leaving...");
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }}
说明: 默认是非公平的 进来一个线程获取许可, 则state减1,直到值为0 以下是源码片段
- final int nonfairTryAcquireShared(int acquires) {//acquires值为1
- for (;;) {
- int available = getState();//当前state值
- int remaining = available - acquires;
- if (remaining < 0 ||
- compareAndSetState(available, remaining))//remaining>0 则CAS修改state 成功获取许可
- return remaining;
- }
- }
- //remainimg<0 返回后,执行下面方法
- private void doAcquireSharedInterruptibly(int arg)
- throws InterruptedException {
- final Node node = addWaiter(Node.SHARED);//创建共享型节点加入等待队列 队列为空则仿制头结点并建立联系
- try {
- for (;;) {
- final Node p = node.predecessor();
- if (p == head) {
- int r = tryAcquireShared(arg);//再次尝试获取许可
- if (r >= 0) {//成功获取许可
- setHeadAndPropagate(node, r);
- p.next = null; // help GC
- return;
- }
- }
- if (shouldParkAfterFailedAcquire(p, node) &&
- parkAndCheckInterrupt())
- break;
- }
- } catch (RuntimeException ex) {
- cancelAcquire(node);
- throw ex;
- }
- // Arrive here only if interrupted
- cancelAcquire(node);
- throw new InterruptedException();
- }
3. 示例二(一个生产者与一个消费者 两组信号量 此消彼长 为0阻塞)
- package com.rocky.semaphore;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Semaphore;
- public class ProducerCustomRealizeWithSemaphore {
- public static void main(String[] args) {
- SemaphoreBuffer semaphoreBuffer = new SemaphoreBuffer();
- Producer producer = new Producer(semaphoreBuffer);
- Customer customer = new Customer(semaphoreBuffer);
- ExecutorService service = Executors.newCachedThreadPool();
- service.execute(customer);
- service.execute(producer);
- service.shutdown();
- }
- }
- class SemaphoreBuffer{
- List<Integer> list = new ArrayList<Integer>();
- Semaphore producerSemaphore = new Semaphore(1);// 允许并行的线程数为1
- Semaphore customerSemaphore = new Semaphore(0);// 0即state的初始值 则一开始消费就阻塞了 见上例说明中remaining<0
- public void put(int num){
- try {
- producerSemaphore.acquire();
- try {
- list.add(num);
- } finally{
- customerSemaphore.release();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- public int get(){
- try {
- customerSemaphore.acquire();
- try{
- return list.remove(0);
- }finally{
- producerSemaphore.release();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return 0;
- }
- }
- class Customer implements Runnable{
- private SemaphoreBuffer buffer;
- Customer(SemaphoreBuffer buffer){
- this.buffer = buffer;
- }
- @Override
- public void run() {
- while(!Thread.interrupted()){
- int num = buffer.get();
- System.out.println("Customer get the num "+num);
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- class Producer implements Runnable{
- private SemaphoreBuffer buffer;
- Producer(SemaphoreBuffer buffer){
- this.buffer = buffer;
- }
- int c =0;
- @Override
- public void run() {
- while(!Thread.interrupted()){
- buffer.put(c);
- System.out.println("Producer put the num "+c);
- c++;
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
4. 示例三(多个生产者与多个消费者 运用阻塞队列 线程安全 )
- package com.rocky.semaphore;
- import java.util.concurrent.BlockingQueue;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.LinkedBlockingDeque;
- import java.util.concurrent.LinkedBlockingQueue;
- import java.util.concurrent.Semaphore;
- import java.util.concurrent.atomic.AtomicInteger;
- public class ProducerCustomRealizeWithSemaphoreLinkedBlockingQueue {
- static AtomicInteger c = new AtomicInteger(1);
- public static void main(String[] args) {
- ExecutorService service = Executors.newCachedThreadPool();
- CakeStand stand = new CakeStand();
- service.execute(new CakeProducer(stand, "producer1", c));
- service.execute(new CakeProducer(stand, "producer2", c));
- service.execute(new CakeProducer(stand, "producer3", c));
- service.execute(new CakeCustomer(stand, "customer1"));
- service.execute(new CakeCustomer(stand, "customer2"));
- }
- }
- class Cake{
- private String name;
- Cake(String name){
- this.name = name;
- }
- public String toString(){
- return name;
- }
- }
- class CakeStand{
- BlockingQueue<Cake> queue = new LinkedBlockingQueue<Cake>(15);
- Semaphore notFull = new Semaphore(10);//生产信号量
- Semaphore notEmpty = new Semaphore(0);//消费信号量
- public void put(Cake cake){
- try {
- notFull.acquire();
- try{
- queue.put(cake);
- }finally{
- notEmpty.release();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- public Cake take(){
- try {
- notEmpty.acquire();
- try{
- Cake cake = queue.take();
- return cake;
- }finally{
- notFull.release();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return null;
- }
- }
- class CakeProducer implements Runnable{
- private CakeStand stand;
- private String name;
- private AtomicInteger c;
- public CakeProducer(CakeStand stand, String name, AtomicInteger c) {
- this.stand = stand;
- this.name = name;
- this.c = c;
- }
- @Override
- public void run() {
- while(!Thread.interrupted()){
- String str = "cake-"+c.getAndIncrement();
- System.out.println("生产:"+name+"-"+str);
- stand.put(new Cake(str));
- try {
- Thread.sleep(1500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- class CakeCustomer implements Runnable{
- private CakeStand stand;
- private String name;
- public CakeCustomer(CakeStand stand, String name){
- this.stand = stand;
- this.name = name;
- }
- @Override
- public void run() {
- while(!Thread.interrupted()){
- Cake cake = stand.take();
- System.err.println("消费:"+name+"-"+cake.toString());
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
说明1): 传统的消费者 生产者使用wait/notify模式等待和相互唤醒, Semaphore通过信号量的值控制运行(>0)和阻塞(<=0),
两组信号量可以使两组角色彼此唤醒,使用阻塞队列可以确保线程安全。
2) 可以额外创建一个信号量Semaphore mutex = new Semaphore(1); 在获取本组信号量之后再获取metex信号量可以实现互斥锁效果
java.util.concurrent.Semaphore 使用的更多相关文章
- 161207、高并发:java.util.concurrent.Semaphore实现字符串池及其常用方法介绍
实现字符串池: StrPool.java import java.util.ArrayList; import java.util.List; import java.util.concurrent. ...
- 聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore
前几篇分析了一下AQS的原理和实现.这篇拿Semaphore信号量做样例看看AQS实际是怎样使用的. Semaphore表示了一种能够同一时候有多个线程进入临界区的同步器,它维护了一个状态表示可用的票 ...
- [转载] java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger
转载自http://janeky.iteye.com/blog/770393 ------------------------------------------------------------- ...
- Java 并发工具包 java.util.concurrent 用户指南
1. java.util.concurrent - Java 并发工具包 Java 5 添加了一个新的包到 Java 平台,java.util.concurrent 包.这个包包含有一系列能够让 Ja ...
- Java并发编程-并发工具包(java.util.concurrent)使用指南(全)
1. java.util.concurrent - Java 并发工具包 Java 5 添加了一个新的包到 Java 平台,java.util.concurrent 包.这个包包含有一系列能够让 Ja ...
- java.util.concurrent包API学习笔记
newFixedThreadPool 创建一个固定大小的线程池. shutdown():用于关闭启动线程,如果不调用该语句,jvm不会关闭. awaitTermination():用于等待子线程结束, ...
- java.util.concurrent 多线程框架
http://daoger.iteye.com/blog/142485 JDK5中的一个亮点就是将Doug Lea的并发库引入到Java标准库中.Doug Lea确实是一个牛人,能教书,能出书,能编码 ...
- Java_并发工具包 java.util.concurrent 用户指南(转)
译序 本指南根据 Jakob Jenkov 最新博客翻译,请随时关注博客更新:http://tutorials.jenkov.com/java-util-concurrent/index.html.本 ...
- 013-并发编程-java.util.concurrent.locks之-AbstractQueuedSynchronizer-用于构建锁和同步容器的框架、独占锁与共享锁的获取与释放
一.概述 AbstractQueuedSynchronizer (简称AQS),位于java.util.concurrent.locks.AbstractQueuedSynchronizer包下, A ...
随机推荐
- php-elasticsearch scroll分页详解
背景 ps:首先我们在一个索引里面写入一万条以上的数据.作为数据源 现在我想看到第一万零一条数据,首先第一想法是,from 10000 size 1 ,这样做会包下面错误.显然是不成立的.此时便会用到 ...
- Web开发模式
原文链接 开发模式的介绍(完善版) 在Web开发模式中,有两个主要的开发结构,称为模式一(Mode I)和模式二(Mode II). 首先我们来理清一些概念吧: DAO(Data Access Obj ...
- tomcat增加运行内存
内容为: set JAVA_OPTS=%JAVA_OPTS% -server -Xms2048m -Xmx2048m -XX:PermSize=212M -XX:MaxPermSize=512m 在m ...
- C#集合之位数组
如果需要处理的数字有许多位,就可以使用BitArray类和BitVector32结构.BitArray类位于System.Collection,BitVector32结构位于System.Collec ...
- eAccelerator 配置参数详解
eAccelerator配置参数如下: [eaccelerator]extension=eaccelerator.soeaccelerator.shm_size="64"eacce ...
- Windows USB 编程
GUID #include <initguid.h> // For DEFINE_GUID // Device Interface GUID.DEFINE_GUID(GUID_DEVINT ...
- Git版本回退和撤销修改
版本回退: 在实际工作中,我们会不断对文件进行修改,然后不断提交修改到版本库里,一旦你把文件改乱了,或者误删了文件,还可以从最近的一个commit恢复,然后继续工作,而不是把几个月的工作成果全部丢失. ...
- CentOS下安装官方RPM包的MySQL后找不到my.cnf
PS:昨天一同事问我说他用MySQL 5.5官方的rpm包安装了,但是在/etc/下面没有my.cnf配置文件.官方rpm包安装的mysql默认确实是没有/etc/my.cnf. 为什么没有这个文件而 ...
- RequireJs学习笔记之data-main Entry Point
You will typically use a data-main script to set configuration options and then load the first appli ...
- Log4J 配置文件模板及代码说明
相对而言,这个日志系统的配置就没那么随意了,而且有些功能用起来也不是那么爽,譬如动态读取配置文件.不过鉴于使用这个日志的系统还是很多,所以也写一个demo贴出来,风格跟log4j2一样,配置的说明全在 ...