jdk 源码分析(17)java Semaphore 源码解析及与lock对比

来源:互联网 发布:大连爱知时计 编辑:程序博客网 时间:2024/05/22 07:09
如果说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 的时候能找到线程。
  1. private void doAcquireSharedInterruptibly(int arg)
  2. throws InterruptedException {
  3.            //加入队列
  4. final Node node = addWaiter(Node.SHARED);
  5. boolean failed = true;
  6. try {
  7. for (;;) {
  8. final Node p = node.predecessor();
  9. if (p == head) {
  10. int r = tryAcquireShared(arg);
  11. if (r >= 0) {
  12. setHeadAndPropagate(node, r);
  13. p.next = null; // help GC
  14. failed = false;
  15. return;
  16. }
  17. }
  18.                 //park 一下
  19. if (shouldParkAfterFailedAcquire(p, node) &&
  20. parkAndCheckInterrupt())
  21. throw new InterruptedException();
  22. }
  23. } finally {
  24. if (failed)
  25. cancelAcquire(node);
  26. }
  27. }

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没区别了。
阅读全文
0 0
原创粉丝点击