如果说countDownLatch和lock 相似,semaphore和lock原理基本就是相同了。如果你对lock过程不了解,建议先看
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没区别了。