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

如果说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 的时候能找到线程。
     
     
  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没区别了。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值