先做总结:

1、Semaphore是什么?

Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。

把它比作是控制流量的红绿灯,比如XX马路要限制流量,只允许同时有一百辆车在这条路上行使,其他的都必须在路口等待,所以前一百辆车会看到绿灯,可以开进这条马路,后面的车会看到红灯,不能驶入XX马路,但是如果前一百辆中有五辆车已经离开了XX马路,那么后面就允许有5辆车驶入马路,这个例子里说的车就是线程,驶入马路就表示线程在执行,离开马路就表示线程执行完成,看见红灯就表示线程被阻塞,不能执行。

2、Semaphore实现原理:

(1)semaphore实际是允许count个线程同时获取的共享锁。(semaphore = new Semaphore(count); 通过AQS实现,count即state)

(2)semaphore.acquire(); 获取semaphore的锁,

    state>0:还有数量,可以获取锁,state - 1;

    state<=0:线程数量已满,不能获取锁,需要将线程挂起并放入等待队列;

(3)semaphore.release(); 释放semaphore的锁,就是将 state+1 释放成功后,唤醒同步队列中的线程

一、应用举例

/**
* 为了简单起见我们假设停车场仅有5个停车位,一开始停车场没有车辆所有车位全部空着,然后先后到来三辆车,停车场车位够,安排进去停车。
* 然后又来三辆,这个时候由于只有两个停车位,所有只能停两辆,其余一辆必须在外面候着,直到停车场有空车位。
* 当然以后每来一辆都需要在外面候着。当停车场有车开出去,里面有空位了,则安排一辆车进去(至于是哪辆 要看选择的机制是公平还是非公平)。
*
* 从程序角度看,停车场就相当于信号量Semaphore,其中许可数为5,车辆就相对线程。
* 当来一辆车时,许可数就会减 1 ,当停车场没有车位了(许可书 ==0 ),其他来的车辆需要在外面等候着。
* 如果有一辆车开出停车场,许可数 + 1,然后放进来一辆车。
*/
class SemaphoreTest { static class Parking {
// 信号量
private Semaphore semaphore; Parking(int count) {
semaphore = new Semaphore(count);
} public void park() {
try {
// 获取信号量
semaphore.acquire();
long time = (long) (Math.random() * 10);
System.out.println(Thread.currentThread().getName() + "进入停车场,停车" + time + "秒...");
Thread.sleep(time);
System.out.println(Thread.currentThread().getName() + "开出停车场...");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
} static class Car extends Thread {
Parking parking; Car(Parking parking) {
this.parking = parking;
} @Override
public void run() {
parking.park(); // 进入停车场
}
} public static void main(String[] args) {
Parking parking = new Parking(3); for (int i = 0; i < 5; i++) {
new Car(parking).start();
}
} /** 输出结果
* Thread-1进入停车场,停车2秒...
* Thread-2进入停车场,停车5秒...
* Thread-0进入停车场,停车3秒...
* Thread-1开出停车场...
* Thread-3进入停车场,停车0秒...
* Thread-3开出停车场...
* Thread-4进入停车场,停车0秒...
* Thread-4开出停车场...
* Thread-0开出停车场...
* Thread-2开出停车场...
*/
}

二、类结构

public class Semaphore implements java.io.Serializable {
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {}
static final class FairSync extends Sync {}
static final class NonfairSync extends Sync {}
}

三、原理解析

    // new Semaphore(count),将AQS的state设置成许可数量count
semaphore = new Semaphore(count); public Semaphore(int permits) {
sync = new NonfairSync(permits);
} Sync(int permits) {
setState(permits);
}
    /**
* 获取semaphore的锁,
* 获取到锁就可以继续操作,没有获取到锁就进入同步队列挂起
*/
semaphore.acquire(); public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
} /**
* state>0:还有数量,可以获取锁
* state<=0:线程数量已满,不能获取锁,需要将线程挂起
*/
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
    /**
* 释放semaphore的锁,就是将state+1
* 释放成功后,唤醒同步队列中的下一个线程
*/
semaphore.release(); public void release() {
sync.releaseShared(1);
} public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
} protected final boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
if (compareAndSetState(current, next))
return true;
}
}

并发工具类(三)控制并发线程数的Semaphore

【死磕Java并发】—–J.U.C之并发工具类:Semaphore

Java并发(十五):并发工具类——信号量Semaphore的更多相关文章

  1. Java多线程并发工具类-信号量Semaphore对象讲解

    Java多线程并发工具类-Semaphore对象讲解 通过前面的学习,我们已经知道了Java多线程并发场景中使用比较多的两个工具类:做加法的CycliBarrier对象以及做减法的CountDownL ...

  2. java十五个常用类学习及方法举例

    <code class="language-java">import java.util.Scanner; import java.util.Properties; i ...

  3. 线程高级应用-心得6-java5线程并发库中同步工具类(synchronizers),新知识大用途

    1.新知识普及 2. Semaphore工具类的使用案例 package com.java5.thread.newSkill; import java.util.concurrent.Executor ...

  4. Java操作文件夹的工具类

    Java操作文件夹的工具类 import java.io.File; public class DeleteDirectory { /** * 删除单个文件 * @param fileName 要删除 ...

  5. Java汉字转成汉语拼音工具类

    Java汉字转成汉语拼音工具类,需要用到pinyin4j.jar包. import net.sourceforge.pinyin4j.PinyinHelper; import net.sourcefo ...

  6. Java核心技术第五章——1.类、超类、子类(2)

    继上一篇Java核心技术第五章——1.类.超类.子类(1) 6.重载解析 假如调用ClassName.Method(args) 1.编译器列出类ClassName所有名为Method的方法. 2.编译 ...

  7. java中excel导入\导出工具类

    1.导入工具 package com.linrain.jcs.test; import jxl.Cell; import jxl.Sheet; import jxl.Workbook; import ...

  8. java中定义一个CloneUtil 工具类

    其实所有的java对象都可以具备克隆能力,只是因为在基础类Object中被设定成了一个保留方法(protected),要想真正拥有克隆的能力, 就需要实现Cloneable接口,重写clone方法.通 ...

  9. “全栈2019”Java第九十五章:方法中可以定义静态局部内部类吗?

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

随机推荐

  1. inviteflood 洪泛滥工具

    inviteflood是一种通过UDP/IP执行SIP/SDP INVITE消息泛洪的工具,描述可以参考:inviteflood Package Description 使用inviteflood工具 ...

  2. 一文轻松搞懂redis集群原理及搭建与使用

    今天早上由于zookeeper和redis集群不在同一虚拟机导致出了点很小错误(人为),所以这里总结一下redis集群的搭建以便日后所需同时也希望能对你有所帮助. 笔主这里使用的是Centos7.如果 ...

  3. 136.Single Number---异或、位运算

    题目链接 题目大意:给出一串数组,里面的数都是两个,只有一个数是一个,把这个只有一个的数找出来.时间复杂度最好是线性的,空间复杂度最好为O(1). 法一:利用map,空间换时间,代码如下(耗时26ms ...

  4. openjudge-NOI 2.6-2988 计算字符串距离

    题目链接:http://noi.openjudge.cn/ch0206/2988/ 题解: 首先,题目有误,少了一个添加操作 和求解LCS之类的思路类似 f[i][j]表示a序列中1..i的部分和b序 ...

  5. [ python ] 字典的使用

    数据类型划分:    可变数据类型:list.dict.set    不可哈希    不可变数据类型:tuple.bool.int.str    可哈希 字典 python内置了字典类型,使用键-值( ...

  6. ECharts图表tooltip显示时超出canvas图层解决方法

    我们在做ECharts图表的时候可能会遇到tooltip显示时超出了canvas图层范围,并且被其它z-index较高的div容器遮盖,这是悬浮展示信息就看不全,我们根据官网文档的配置项查询发现con ...

  7. rcnn ->fast rcnn->faster rcnn物体检测论文

    faster rcnn中的rpn网络: 特征可以看做一个尺度51*39的256通道图像,对于该图像的每一个位置,考虑9个可能的候选窗口:三种面积{1282,2562,5122}×三种比例{1:1,1: ...

  8. strcpy、memcpy和memset之间的区别

    今天刷题时遇到了这个问题,记录一下. strcpy比较简单,就是拷贝字符串,遇到'\0'时结束拷贝. memcpy用来做内存拷贝,可以拷贝任何数据类型的对象并指定拷贝数据的长度:char a[100] ...

  9. 1、量化投资—为什么选择Python?

    Python在量化领域的现状 就跟Java在web领域无可撼动的地位一样,Python也已经在金融量化投资领域占据了重要位置,从各个业务链条都能找到相应的框架实现. 在量化投资(证券和比特币)开源项目 ...

  10. 洛谷P2676 超级书架 题解

    题目传送门 题目一看就是贪心.C++福利来了:sort. 基本思路就是:要使奶牛最少那么肯定高的奶牛先啦. 直接排序一遍(从高到矮)然后while,搞定! #include<bits/stdc+ ...