Semaphore源码剖析

Semaphore源码剖析

Semaphore从英⽂单词上翻译是:信号量,可以理解 他是⼀个 许可证。只有获取到 许可证 的线程,才能执⾏相应逻辑,同时拿⾛ 许可证,⽽那些没有获取到的线程 只能等待。当持有 许可证 的线程 执⾏完成 后,需要 归还 许可证, 下⼀个线程 才可以 获取 许可证 执⾏相应逻辑。

测试案例:

public class SemaphoreDemo {

    public static void main(String[] args) {
        SemaphoreDemo demo = new SemaphoreDemo();
        demo.test();
    }

    private void test() {
        // 停车场同时容纳的车辆 5
        Semaphore semaphore = new Semaphore(5);
        List<Thread> threadList = new ArrayList<>();
        // 模拟 8 辆车进入停车场
        for (int i = 0; i < 8; i++) {
            threadList.add(new Thread(() -> this.park(semaphore)));
        }
        threadList.forEach(Thread::start);
    }

    private void park(Semaphore semaphore) {
        try {
            Random random = new Random();
            int seconds = random.nextInt(4) + 2;
            System.out.println(Thread.currentThread().getName() + " --> 来到停车场");
            if (semaphore.availablePermits() == 0) {
                System.err.println(Thread.currentThread().getName() + " --> 车位不足,请耐心等待");
            }
            semaphore.acquire();// 获取令牌尝试进入停车场
            System.out.println(Thread.currentThread().getName() + " --> 成功进入停车场 停留时间 [" + seconds + "] 秒");
            Thread.sleep(seconds * 1000);
            System.out.println(Thread.currentThread().getName() + " --> 驶出停车场");
            semaphore.release();//释放令牌,腾出停车场车位
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

Thread-3 --> 来到停车场
Thread-4 --> 来到停车场
Thread-0 --> 来到停车场
Thread-2 --> 来到停车场
Thread-5 --> 来到停车场
Thread-1 --> 来到停车场
Thread-7 --> 来到停车场
Thread-6 --> 来到停车场
Thread-3 --> 成功进入停车场 停留时间 [2] 秒
Thread-7 --> 成功进入停车场 停留时间 [3] 秒
Thread-4 --> 成功进入停车场 停留时间 [2] 秒
Thread-1 --> 成功进入停车场 停留时间 [4] 秒
Thread-2 --> 成功进入停车场 停留时间 [4] 秒
Thread-6 --> 车位不足,请耐心等待
Thread-4 --> 驶出停车场
Thread-3 --> 驶出停车场
Thread-5 --> 成功进入停车场 停留时间 [5] 秒
Thread-6 --> 成功进入停车场 停留时间 [2] 秒
Thread-7 --> 驶出停车场
Thread-0 --> 成功进入停车场 停留时间 [2] 秒
Thread-2 --> 驶出停车场
Thread-6 --> 驶出停车场
Thread-1 --> 驶出停车场
Thread-0 --> 驶出停车场
Thread-5 --> 驶出停车场

常用方法源码剖析:

public class Semaphore implements java.io.Serializable {
	private final Sync sync;
	
    abstract static class Sync extends AbstractQueuedSynchronizer {
        .....
    }
    
    // permits:表示允许同时执行任务的线程个数,
    // 底层其实是给aqs的state变量进行赋值
    public Semaphore(int permits) {
        // 默认使用非公平锁
        sync = new NonfairSync(permits);
    }
    
    // 同上,fair=true时,使用公平锁
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }
    
    // 查看是否有可用的令牌
    public int availablePermits() {
        return sync.getPermits();// 底层就是直接获取的aqs的state的值
    }
    
    // 获取令牌
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    
    // 见读写锁该方法的解析
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }
    
    // 公平锁实现
    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;
        }
    }
    // 非公平锁实现
    protected int tryAcquireShared(int acquires) {
        return nonfairTryAcquireShared(acquires);
    }
    
    // 上来就直接开干
    final int nonfairTryAcquireShared(int acquires) {
        for (;;) {
            int available = getState();
            int remaining = available - acquires;
            if (remaining < 0 ||
                compareAndSetState(available, remaining))
                return remaining;
        }
    }
    
    // 释放令牌
    public void release() {
        sync.releaseShared(1);
    }
    
    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }
    
    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;
        }
    }

}

总结:Semaphore底层其实还是基于AQS的state变量来进行操作的。

posted on 2024-09-02 17:05  ~码铃薯~  阅读(4)  评论(0编辑  收藏  举报

导航