《java.util.concurrent 包源码阅读》17 信号量 Semaphore
学过操作系统的朋友都知道信号量,在java.util.concurrent包中也有一个关于信号量的实现:Semaphore。
从代码实现的角度来说,信号量与锁很类似,可以看成是一个有限的共享锁,即只能被有限数量的线程使用的共享锁。
因为存在计数,因此Semaphore的构造函数有参数permits来设定计数:
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
涉及到线程排队等待的问题,Semaphore也支持fair和unfair模式:
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
说到线程排队,前面在说“锁”的时候讲过AbstractQueuedSynchronizer,它实现了类似获取锁失败,管理等待的线程的功能。因此信号量的实现同样需要借助这个类。
abstract static class Sync extends AbstractQueuedSynchronizer // Unfair模式的实现
static final class NonfairSync extends Sync // Fair模式的实现
static final class FairSync extends Sync
Sync类使用AbstractQueuedSynchronizer的state来存储信号量的计数:
Sync(int permits) {
setState(permits);
}
因为信号量与共享锁类似,因此在获取资源和释放资源的时候使用的都是AbstractQueuedSynchronizer的shared类型的方法。
再次回到前面的unfair和fair模式,这种所谓的公平体现在获取锁的时候:unfair是后来先得,fair是先来先得。来看两者的尝试获取资源的方法:
// unfair模式
final int nonfairTryAcquireShared(int acquires) {
// 直接检查是不是有资源,根本不看前面有没有其他排队的
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
} // fair模式
protected int tryAcquireShared(int acquires) {
for (;;) {
// 先看看有没有排队的
if (hasQueuedPredecessors())
return -1;
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
对于信号量来说,获取资源的过程,就是一个更新资源计数的过程。对于释放资源来说,也是一样。
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;
}
}
关于信号量的实现,有了AbstractQueuedSynchronizer和锁的基础,是非常好理解的。
《java.util.concurrent 包源码阅读》17 信号量 Semaphore的更多相关文章
- 《java.util.concurrent 包源码阅读》 结束语
<java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...
- 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分
这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...
- 《java.util.concurrent 包源码阅读》02 关于java.util.concurrent.atomic包
Aomic数据类型有四种类型:AomicBoolean, AomicInteger, AomicLong, 和AomicReferrence(针对Object的)以及它们的数组类型, 还有一个特殊的A ...
- 《java.util.concurrent 包源码阅读》04 ConcurrentMap
Java集合框架中的Map类型的数据结构是非线程安全,在多线程环境中使用时需要手动进行线程同步.因此在java.util.concurrent包中提供了一个线程安全版本的Map类型数据结构:Concu ...
- 《java.util.concurrent 包源码阅读》06 ArrayBlockingQueue
对于BlockingQueue的具体实现,主要关注的有两点:线程安全的实现和阻塞操作的实现.所以分析ArrayBlockingQueue也是基于这两点. 对于线程安全来说,所有的添加元素的方法和拿走元 ...
- 《java.util.concurrent 包源码阅读》09 线程池系列之介绍篇
concurrent包中Executor接口的主要类的关系图如下: Executor接口非常单一,就是执行一个Runnable的命令. public interface Executor { void ...
- 《java.util.concurrent 包源码阅读》24 Fork/Join框架之Work-Stealing
仔细看了Doug Lea的那篇文章:A Java Fork/Join Framework 中关于Work-Stealing的部分,下面列出该算法的要点(基本是原文的翻译): 1. 每个Worker线程 ...
- 《java.util.concurrent 包源码阅读》25 Fork/Join框架之Fork与Work-Stealing(重写23,24)
在写前面两篇文章23和24的时候自己有很多细节搞得不是很明白,这篇文章把Fork和Work-Stealing相关的源代码重新梳理一下. 首先来看一些线程池定义的成员变量: 关于scanGuard: v ...
- 《java.util.concurrent 包源码阅读》05 BlockingQueue
想必大家都很熟悉生产者-消费者队列,生产者负责添加元素到队列,如果队列已满则会进入阻塞状态直到有消费者拿走元素.相反,消费者负责从队列中拿走元素,如果队列为空则会进入阻塞状态直到有生产者添加元素到队列 ...
随机推荐
- wordpress 源代码 高亮显示 (Crayon Syntax Highlighter)
作为码农,blog 里面不贴源代码像什么话,源代码没有高亮显示,那还怎么看!一番调研之后,Crayon Syntax Highlighter 可能是最流行,功能最强大的一款代码高亮插件了. 一.安装 ...
- 突发小事件,USB接口问题
昨天遇到的突发事件,突然USB接口全部瘫了,键盘鼠标全部不能用,换到别人电脑上可以,吓尿了,以为本子主板挂了,但是发现插U盘竟然可以识别而且可以打开,感觉可能是静电问题,果然,彻底关机,拔掉电池,然后 ...
- github上传项目
前置说明: 1.github上已经创建好的repositories,没有的可以自己创建一个 2.已经安装好的git,下载源推荐https://pan.baidu.com/s/1kU5OCOB#list ...
- LeetCode 18. 4Sum (四数之和)
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = tar ...
- 为什么C++没有对应realloc的new操作符呢?
http://blog.csdn.net/rabbit729/article/details/3400260 这个用memcpy明显是有问题的.如果类有资源分配的话,直接memcpy不能复制资源,会导 ...
- cmd 编译java WebService
格式:wsimport -s "src目录" -p "生成类所在包名" -keep "wsdl发布地址" 示例: wsimport -s G ...
- iOS 之 UITextField
UITextField 相关细节处理: 1. 设置leftView , rightView let leftView = UIView() // 设置leftView/rightView之后,勿忘设 ...
- 使用bower init创建bower.json文件
使用bower init 可以快速创建bower.json文件 bower init 回答一系列问题后就可以了,其中大部分问题可以按enter跳过.
- Python学习之二:Python 与 C 区别
引自http://www.lxway.com/181844.htm 从开始看Python到现在也有半个多月了,前后看了Python核心编程和Dive into Python两本书.话说半个月看两本,是 ...
- (转)linux下如何批量杀JAVA进程或某个进程方法
在工作中经常需要停止JAVA进程,停止时间也比较长,那么有时候因为一些情况,需要把 linux 下JAVA所有进程 kill 掉,又不能用killall 直接杀掉某一进程名称包含的所有运行中进程(我们 ...