Java系列之Semaphore

版权声明: https://blog.csdn.net/ph3636/article/details/84944157

1. Semaphore用来控制同时允许的操作的令牌数量,分为公平和非公平,核心类Sync继承AbstractQueuedSynchronizer

public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

2. 尝试获取令牌,数量可以自己设置,这个对于两种Sync都是一样的操作。

public boolean tryAcquire(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.nonfairTryAcquireShared(permits) >= 0;
    }

死循环尝试获取,直到没有对应的数量返回负数,获取成功后通过原子操作设置剩余量。

final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }

3. 带有限时的尝试获取令牌,数量可以自己设置,这个对于两种Sync都是一样的操作。

public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
        throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
    }

父类AbstractQueuedSynchronizer

  public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquireShared(arg) >= 0 ||
            doAcquireSharedNanos(arg, nanosTimeout);
    }

子类Sync必须要实现的方法tryAcquireShared尝试获取共享锁

protected int tryAcquireShared(int arg) {
        throw new UnsupportedOperationException();
    }

非公平类NonfairSync

protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }

公平类FairSync,他们的区别在于FairSync先判断当前有没有已经等待的其他线程,因为要保证顺序,当令牌数量充足时,该队列中不会有值,当队列中有值并且第一个等待线程不是本线程则会把本线程加入到等待队列中

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

4. 直接获取对应数量的令牌,可被中断获取操作

public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);
    }

 public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

不能被中断的获取操作

 public void acquireUninterruptibly(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireShared(permits);
    }

public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }

最后都是调用的是tryAcquireShared获取令牌。

5. 释放对应的令牌数

public void release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.releaseShared(permits);
    }

父类方法

 protected boolean tryReleaseShared(int arg) {
        throw new UnsupportedOperationException();
    }

子类实现方法,循环使用原子操作设置数量。

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");
                if (compareAndSetState(current, next))
                    return true;
            }
        }

6. 这个令牌许可数量是可以动态变动的,许多程序中会这样使用Semaphore s = new Semaphore(0),然后有个地方在一直尝试获取令牌,这样的话该线程的执行时刻自己就可以用s.release(1)来控制,当然也可以多次release,因为它释放的令牌是可以累加的,初始数量为0,但是执行两次release的话,许可量就会变成2,并不完全由初始构造函数来控制。

猜你喜欢

转载自blog.csdn.net/ph3636/article/details/84944157