Semaphore

简介

Semaphore信号量,用来控制同时访问特定资源的线程数量,他通过协调各个线程,以保证合理地使用公用资源。

内部类

abstract static class Sync extends AbstractQueuedSynchronizer {}

// 非公平锁
static final class NonfairSync extends Sync {
    private static final long serialVersionUID = -2694183684443567898L;

    NonfairSync(int permits) {
        super(permits);
    }
    // 尝试获取共享锁
    protected int tryAcquireShared(int acquires) {
        return nonfairTryAcquireShared(acquires);
    }
}

// 公平锁
static final class FairSync extends Sync {
    private static final long serialVersionUID = 2014338818796000944L;

    FairSync(int permits) {
        super(permits);
    }

    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;
        }
    }
}

非公平锁

// 默认为非公平锁
Semaphore semaphore = new Semaphore(10);
// 获取许可,将同步状态减1
semaphore.acquire();

// Semaphore.acquire()
public void acquire() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

// AbstractQueuedSynchronizer.acquireSharedInterruptibly(int arg)
public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
    // 若当前线程已经中断,则抛出异常
    if (Thread.interrupted())
        throw new InterruptedException();
    // tryAcquireShared尝试获取锁,该方法由AbstractQueuedSynchronizer的子类实现
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg); // 若尝试获取许可失败,则需要进行排队
}

// Semaphore.NonfairSync.tryAcquireShared(int acquires)
// 尝试获取许可
protected int tryAcquireShared(int acquires) {
    return nonfairTryAcquireShared(acquires);
}

// Semaphore.Sync.nonfairTryAcquireShared(int acquires)
// 非公平锁获取许可
final int nonfairTryAcquireShared(int acquires) {
    for (;;) {
        // 这里使用for循环不断地进行CAS操作
        // 获取许可数
        int available = getState();
        // 减去当前线程需要的许可,得到剩余的许可数
        int remaining = available - acquires;
        // 如果剩余许可数小于0,则直接返回,获取许可失败
        // 如果剩余许可数不小于0,则尝试原子更新state的值,成功了返回剩余许可数
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}

// AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(int arg)
// 若前面尝试获取许可失败,则加入到同步队列进行排队
private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
    // 构造一个节点加入到同步队列中,在 ReentrantLock 章节已经分析过这个方法
    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;
                }
            }
            // shouldParkAfterFailedAcquire和parkAndCheckInterrupt的实现方式与ReentrantLock一样
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node); // 将节点取消
    }
}

// 释放许可
semaphore.release();

// Semaphore.release()
public void release() {
    sync.releaseShared(1);
}

// AbstractQueuedSynchronizer.releaseShared(int arg)
// 释放许可
public final boolean releaseShared(int arg) {
    // 尝试释放许可
    if (tryReleaseShared(arg)) {
        doReleaseShared(); // 若释放许可成功,则通知下一个节点
        return true;
    }
    return false;
}

// Semaphore.NonfairSync.tryReleaseShared(int releases)
// 释放锁,相当于许可加1
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");
         // 这里使用for循环不断地进行CAS操作,直到更新同步状态成功为止
        if (compareAndSetState(current, next))
            return true;
    }
}

公平锁

Semaphore semaphore = new Semaphore(10,true);

semaphore.acquire();
// Semaphore.acquire()
public void acquire() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

// AbstractQueuedSynchronizer.acquireSharedInterruptibly(int arg)
public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
    // 若当前线程已经中断,则抛出异常
    if (Thread.interrupted())
        throw new InterruptedException();
    // tryAcquireShared 尝试获取锁,该方法由AbstractQueuedSynchronizer的子类实现
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg); // 若尝试获取许可失败,则需要进行排队
}

// Semaphore.FairSync.tryAcquireShared(int acquires)
protected int tryAcquireShared(int acquires) {
    for (;;) {
        // 与非公平锁不同的地方就是这里多了一个判断
        // 如果等待队列不为空,并且等待队列的下一个节点不为当前节点,则不能尝试获取锁
        // 在 ReentrantLock 章节已经分析过这个方法
        if (hasQueuedPredecessors())
            return -1;
        int available = getState();
        int remaining = available - acquires;
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}

// 后面方法的实现与非公平锁一样
semaphore.release();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值