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 ...
随机推荐
- 「美团 CodeM 复赛」城市网络
题目链接 题意分析 首先 \([u,v]\)在树上是一条深度递增的链 那么我们可以使用倍增找 \(x\)的祖先当中深度最大的值大于\(x\)的点 然后维护一个\(pre\) 重新建树 这样从\(x\) ...
- POJ3321 Apple Tree (JAVA)
树形数组题,有一定难度. 首先得搞清楚树形数组是什么 - 它是建立在原始数组上的统计数组 - 目的:方便对原始数组进行切片统计,主要用于统计切片的累加和 其实你可以对切片进行扫描,把元素一个一个加起来 ...
- ES6 (一)变量声明方法 & 解构赋值
就是最新的JavaScript 原来的是var,要求不严格,不能限制修改,函数级 es6要求严格 1.防止重复声明 let 变量=var const 常量 2.控制修改 const常量不能修 ...
- Intellij IDEA 封装Jar包(提示错误: 找不到或无法加载主类)
封装的过程如下: 然后准备打包 选择Build或者ReBuild即可. 但这样就会引起开始第一个图的问题.提示无法加载主类,另外一个情况就是所有的外部第三方jar包都被封装到一个jar包里面了. 那么 ...
- 干掉Vivado幺蛾子(1)-- Xilinx Tcl Store
目录 1. 安装Xilinx Tcl Store 2. 手动更新 2.1 下载库 2.2 修改环境变量 参考文献: 最近在跟着高亚军老师的分析文章来学习Xilinx最近发布的<UltraFast ...
- 深入理解计算机系统10——系统级I/O
系统级I/O 输入/输出 是在主存和外部设备之间拷贝数据的过程. 外部设备可以是:磁盘驱动器.终端和网络. 输入和输出都是相对于主存而言的. 输入是从I/O设备拷贝数据到主存.输出时从主存拷贝数据到I ...
- 基础篇:6.2)形位公差-符号 Symbol
本章目的:了解定义形位公差的符号. 1.公差特征项目的符号(GM新标准) //形位公差共:5类14个,4,2,3,3,2. 2.附加符号(GM新标准) //①基本尺寸(理论尺寸)没有公差,无需检验(不 ...
- rsa字符串格式公钥转换python rsa库可识别的公钥形式
在爬虫分析的时候,经常在网页上看到如下格式的rsa公钥: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC7kw8r6tq43pwApYvkJ5laljaN9BZb21 ...
- C#只启动一个进程的代码
把写内容过程中经常用到的内容做个收藏,如下的内容是关于C#只启动一个进程的内容.public partial class App : Application { protected override ...
- Servlet入门小案例
案例一:tomcat9.jdk1.8 1.eclipse创建web项目 1)创建一个Dynamic web project,名字为Servlet_hjh 2)在src下创建一个包,为com.hjh.d ...