24. Java JUC源码分析系列笔记-Semaphore

文章目录

  • 1. 是什么
  • 2. 原理分析
    • 2.1. uml
  • 3. 公平信号量
    • 3.1. 是什么
    • 3.2. 使用
    • 3.3. 原理分析
      • 3.3.1. 构造方法
        • 3.3.1.1. 公平Sync
      • 3.3.2. acquire
        • 3.3.2.1. 调用AQS加共享锁
          • 3.3.2.1.1. 尝试加锁【公平:队列前面有人排队那么直接返回失败】
      • 3.3.3. release
        • 3.3.3.1. 调用AQS释放共享锁
          • 3.3.3.1.1. 尝试释放共享锁
  • 4. 非公平信号量
    • 4.1. 是什么
    • 4.2. 使用
    • 4.3. 原理分析
      • 4.3.1. 构造方法
        • 4.3.1.1. 非公平Sync
      • 4.3.2. acquire
        • 4.3.2.1. 调用AQS加共享锁
          • 4.3.2.1.1. 尝试加共享锁【非公平:不管队列前面是否有人我直接尝试加锁】
      • 4.3.3. release
        • 4.3.3.1. 调用AQS释放共享锁
          • 4.3.3.1.1. 尝试释放锁

1. 是什么

限流工具类,同一时间只允许n个线程访问某资源

2. 原理分析

2.1. uml

@startuml
skinparam classAttributeIconSize 0

class Semaphore{
}

class AbstractQueuedSynchronizer{
}

class Sync{
}

class FairSync{
}

class NonfairSync{

}

Sync <|-- FairSync

Sync <|-- NonfairSync

AbstractQueuedSynchronizer <|-- Sync

Semaphore --> Sync
@enduml

可以看出Semaphore也有公平的和非公平之分

3. 公平信号量

3.1. 是什么

限流,使用的公平策略

3.2. 使用

public class SemaphoreTest
{
    private final static int THREAD_COUNT = 100;
    private final static CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT);

    public static void main(String[] args) throws InterruptedException
    {
        Semaphore semaphore = new Semaphore(10, true);//true代表公平

        for (int i = 0; i < THREAD_COUNT; i++)
        {
            new Thread(()->{
                try
                {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "正在访问资源。。。");
                    TimeUnit.SECONDS.sleep(3);

                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
                finally
                {
                    semaphore.release();
                    countDownLatch.countDown();
                }
            }).start();
        }

        countDownLatch.await();
    }
}

3.3. 原理分析

3.3.1. 构造方法

public Semaphore(int permits, boolean fair) {
    //公平用的是FairSync
    sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
3.3.1.1. 公平Sync
  • FairSync
static final class FairSync extends Sync {
    private static final long serialVersionUID = 2014338818796000944L;

    FairSync(int permits) {
        //Semaphore.Sync#Sync
        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;
        }
    }
}
  • Sync
abstract static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 1192457210091910933L;

    Sync(int permits) {
        //最终就是设置了permits个信号量
        setState(permits);
    }
}

3.3.2. acquire

public void acquire() throws InterruptedException {
    //AQS的acquireSharedInterruptibly
    sync.acquireSharedInterruptibly(1);
}
3.3.2.1. 调用AQS加共享锁
  • AQS acquireSharedInterruptibly
public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    //Semaphore.FairSync重写了tryAcquireShared
    //如果信号量不够那么返回负数,这里执行doAcquireSharedInterruptibly入AQS队,并且阻塞等待唤醒
    //如果信号量够的话返回>=0的数,那么调用此acquire方法的代码就可以继续执行业务代码
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}
3.3.2.1.1. 尝试加锁【公平:队列前面有人排队那么直接返回失败】
  • Semaphore.FairSync#tryAcquireShared
protected int tryAcquireShared(int acquires) {
    for (;;) {
        //如果队列中我的前面有人排队,那么返回-1
        if (hasQueuedPredecessors())
            return -1;
        //当前的信号量
        int available = getState();
        //当前的信号量够不够我获取?
        int remaining = available - acquires;
        //<0表示不够的话返回这个数
        if (remaining < 0 ||
             //>=0说明够了,那么CAS修改剩余信号量
            compareAndSetState(available, remaining))
            return remaining;
    }
}

3.3.3. release

  • Semaphore#release()
public void release() {
    //AQS的releaseShared
    sync.releaseShared(1);
}
3.3.3.1. 调用AQS释放共享锁
  • AQS#releaseShared
public final boolean releaseShared(int arg) {
    //Semaphore.Sync重写了tryReleaseShared
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}
3.3.3.1.1. 尝试释放共享锁
  • Semaphore.Sync#tryReleaseShared
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");
        //CAS修改信号量
        if (compareAndSetState(current, next))
            return true;
    }
}

4. 非公平信号量

4.1. 是什么

限流,使用的非公平策略

4.2. 使用

public class SemaphoreTest
{
    private final static int THREAD_COUNT = 100;
    private final static CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT);

    public static void main(String[] args) throws InterruptedException
    {
        Semaphore semaphore = new Semaphore(10);

        for (int i = 0; i < THREAD_COUNT; i++)
        {
            new Thread(()->{
                try
                {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "正在访问资源。。。");
                    TimeUnit.SECONDS.sleep(3);

                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
                finally
                {
                    semaphore.release();
                    countDownLatch.countDown();
                }
            }).start();
        }

        countDownLatch.await();
    }
}

4.3. 原理分析

4.3.1. 构造方法

public Semaphore(int permits) {
    //创建的是非公平的Sync
    sync = new NonfairSync(permits);
}
4.3.1.1. 非公平Sync
  • NonfairSync
static final class NonfairSync extends Sync {
    private static final long serialVersionUID = -2694183684443567898L;

    NonfairSync(int permits) {
        //调用Sync
        super(permits);
    }

    protected int tryAcquireShared(int acquires) {
        return nonfairTryAcquireShared(acquires);
    }
}
  • Sync
abstract static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 1192457210091910933L;

    Sync(int permits) {
        //最终就是设置了permits个信号量
        setState(permits);
    }
}

4.3.2. acquire

public void acquire() throws InterruptedException {
    //AQS的acquireSharedInterruptibly
    sync.acquireSharedInterruptibly(1);
}
4.3.2.1. 调用AQS加共享锁
  • AQS acquireSharedInterruptibly
public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    //Semaphore.NonfairSync重写了tryAcquireShared
    //如果信号量不够那么返回负数,这里执行doAcquireSharedInterruptibly入AQS队,并且阻塞等待唤醒
    //如果信号量够的话返回>=0的数,那么调用此acquire方法的代码就可以继续执行业务代码
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}
4.3.2.1.1. 尝试加共享锁【非公平:不管队列前面是否有人我直接尝试加锁】
  • Semaphore.NonfairSync#tryAcquireShared
protected int tryAcquireShared(int acquires) {
    return nonfairTryAcquireShared(acquires);
}
  • Semaphore.Sync#nonfairTryAcquireShared
final int nonfairTryAcquireShared(int acquires) {
    for (;;) {
        //当前的信号量
        int available = getState();
        //当前的信号量够不够我获取?
        int remaining = available - acquires;
        //<0表示不够的话返回这个数
        if (remaining < 0 ||
        //>=0说明够了,那么CAS修改剩余信号量
            compareAndSetState(available, remaining))
            return remaining;
    }
}

4.3.3. release

  • Semaphore#release()
public void release() {
    //AQS的releaseShared
    sync.releaseShared(1);
}
4.3.3.1. 调用AQS释放共享锁
  • AQS#releaseShared
public final boolean releaseShared(int arg) {
    //Semaphore.Sync重写了tryReleaseShared
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}
4.3.3.1.1. 尝试释放锁
  • Semaphore.Sync#tryReleaseShared
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");
        //CAS修改信号量
        if (compareAndSetState(current, next))
            return true;
    }
}

你可能感兴趣的:(Java,JUC源码分析,java,笔记,开发语言)