您的位置:首页 > 编程语言 > Java开发

《java.util.concurrent 包源码阅读》17 信号量 Semaphore

2014-08-26 16:07 525 查看
学过操作系统的朋友都知道信号量,在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和锁的基础,是非常好理解的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐