如果说countDownLatch和lock 相似,semaphore和lock原理基本就是相同了。如果你对lock过程不了解,建议先看
(参考lock:jdk 源码分析(7)java ReentrantLock结构)
1)定义对比
semaphore
public Semaphore(
int permits) {
sync =
new NonfairSync(permits)
;
}
ReentrantLock
public ReentrantLock() {
sync =
new NonfairSync()
;
}
默认都是使用非公平Sync,公平Sync是先到先得,非公平是先前获取一次值,然后才排队。
2)获取信号量和获取lock对比
acquire():会调用acquireSharedInterruptibly,首先会去判断是否state 是否已经达到能请求的数量,如果没有就直接返回false,让线程继续,否则会执行
doAcquireSharedInterruptibly加
入队列中,然后park
public final void acquireSharedInterruptibly(
int arg)
throws InterruptedException {
if (Thread.
interrupted())
throw new InterruptedException()
;
if (tryAcquireShared(arg) <
0)
doAcquireSharedInterruptibly(arg)
;
}
lock(),会调用这个方法
public final void acquire(
int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.
EXCLUSIVE)
, arg))
selfInterrupt()
;
}
上面的
doAcquireSharedInterruptibly
方法,加入队列是为了unpark 的时候能找到线程。
private void doAcquireSharedInterruptibly(int arg) throws InterruptedException { //加入队列
final Node node = addWaiter(Node.SHARED); boolean failed = true; 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 failed = false; return; } } //park 一下
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } }
3)release和unlock对比
release 会调用的方法,又是惊人的相似,先前改变state到可以使用的数目,然后去队列里释放相应数量的线程,不让他们等待了。
public final boolean releaseShared(
int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared()
;
return true;
}
return false;
}
unlock会调用的方法
public final boolean release(
int arg) {
if (tryRelease(arg)) {
Node h =
head;
if (h !=
null && h.
waitStatus !=
0)
unparkSuccessor(h)
;
return true;
}
return false;
}
4)对比release具体实现,是不是很相似。
上面的
doReleaseShared方法
private void doReleaseShared() {
for (
;;) {
Node h =
head;
if (h !=
null && h !=
tail) {
int ws = h.
waitStatus;
if (ws == Node.
SIGNAL) {
if (!
compareAndSetWaitStatus(h
, Node.
SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h)
;
}
else if (ws ==
0 &&
!
compareAndSetWaitStatus(h
, 0, Node.
PROPAGATE))
continue; // loop on failed CAS
}
if (h ==
head)
// loop if head changed
break;
}
}
lock的release。
public final boolean release(
int arg) {
if (tryRelease(arg)) {
Node h =
head;
if (h !=
null && h.
waitStatus !=
0)
unparkSuccessor(h)
;
return true;
}
return false;
}
总结:
应该可以说Semaphore 如果说是一种特殊的lock:(因为大家首先首先lock才这么说,应该是lock是一种特殊的
Semaphore)
1)lock 是独占,一人享用,而Semaphore是一个多人使用,lock是电影院的VIP单人间,
而Semaphore是大厅。
2)lock和Semaphore都需要排队,都有两种排队方式:公平和非公平。
3)lock和Semaphore都是改变state变量,只是lock争夺0变成1,而Semaphore是争一个非零的值,因此几率大很多。
4)如果初始是将permits也是就是state 置为1,那么
Semaphore就和lock没区别了。