JUC源码简析 Semaphore

相关阅读

简介

Semaphore是一个线程同步的辅助类,内部维护了当前访问自身的线程个数,并提供同步机制;
使用Semaphore可以控制同时访问资源的线程个数。

源码简析

内部类——Sync

简介

继承自AbstractQueuedSynchronizer,重写了父类的tryReleaseShared方法;提供了nonfairTryAcquireSharedreducePermitsdrainPermits方法;

tryReleaseShared

protected final boolean tryReleaseShared(int releases) {
    // 死循环保证释放锁成功,存在多线程同时修改共享锁资源状态
    for (;;) {
        int current = getState();
        int next = current + releases;
        if (next < current)
            // 资源计数发生反转,需要抛出错误
            throw new Error("Maximum permit count exceeded");
        // CAS尝试更新锁资源
        //     更新失败,存在其它线程同时尝试获取/释放锁,那么需要进行下一循环
        if (compareAndSetState(current, next))
            // true表示释放锁成功
            return true;
    }
}

nonfairTryAcquireShared

final int nonfairTryAcquireShared(int acquires) {
    // 死循环保证尝试获取锁成功若存在共享锁资源的话,存在多线程同时修改共享锁资源状态
    for (;;) {
        int available = getState();
        int remaining = available - acquires;
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            // 无共享锁资源可获取则直接退出,返回当前共享锁资源状态
            // 否则CAS尝试更新锁资源
            //     更新成功,则可以退出,返回当前共享锁资源状态
            //     更新失败,因为存在其它线程同时尝试获取/释放锁,那么需要进行下一循环
            return remaining;
    }
}

reducePermits

final void reducePermits(int reductions) {
    // 死循环保证执行成功,存在多线程同时修改共享锁资源状态
    for (;;) {
        int current = getState();
        int next = current - reductions;
        if (next > current)
            // 资源计数发生反转,需要抛出错误
            throw new Error("Permit count underflow");
        // CAS尝试更新锁资源
        if (compareAndSetState(current, next))
            // 更新成功,则可以退出
            // 更新失败,因为存在其它线程同时尝试获取/释放锁,那么需要进行下一循环
            return;
    }
}

drainPermits

final int drainPermits() {
    // 死循环保证执行成功,存在多线程同时修改共享锁资源状态
    for (;;) {
        int current = getState();
        // 无共享锁资源可获取则直接退出,返回当前共享锁资源状态
        // 否则CAS尝试更新锁资源
        //     更新成功,则可以退出,返回当前共享锁资源状态
        //     更新失败,因为存在其它线程同时尝试获取/释放锁,那么需要进行下一循环
        if (current == 0 || compareAndSetState(current, 0))
            return current;
    }
}

内部类——NonfairSync

简介

继承内部类Sync,实现非公平信号量相关操作;
需要实现的方法为:来自父类Sync继承的AbstractQueuedSynchronizer的抽象方法tryAcquireShared

tryAcquireShared

protected int tryAcquireShared(int acquires) {
    // 直接调用父类Sync的nonfairTryAcquireShared方法实现
    return nonfairTryAcquireShared(acquires);
}

本方式是以不公平竞争锁的方式实现的,不公平的体现为:新线程没有考虑当前是否已存在其它线程在等待获取锁,而是直接尝试获取锁;如果此时持有锁的线程恰好释放锁,那么新线程就可能获取锁成功,被释放锁线程唤醒的后继节点线程会因获取锁失败,再次设置头节点(头节点没有变化)的等待状态为SIGNAL,然后挂起,等待新线程释放锁时唤醒自身;

内部类——FairSync

简介

继承内部类Sync,实现公平信号量相关操作;
需要实现的方法为:来自父类Sync继承的AbstractQueuedSynchronizer的抽象方法tryAcquireShared

tryAcquireShared

protected int tryAcquireShared(int acquires) {
    // 死循环保证执行成功,存在多线程同时修改共享锁资源状态
    for (;;) {
        if (hasQueuedPredecessors())
            // 如果存在等待获取锁的线程,那么直接返回-1,表示获取锁失败
            return -1;
        int available = getState();
        int remaining = available - acquires;
        // 无共享锁资源可获取则直接退出,返回当前共享锁资源状态
        // 否则CAS尝试更新锁资源
        //     更新成功,则可以退出,返回当前共享锁资源状态
        //     更新失败,因为存在其它线程同时尝试获取/释放锁,那么需要进行下一循环
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}

// AbstractQueuedSynchronizer
public final boolean hasQueuedPredecessors() {
    // The correctness of this depends on head being initialized
    // before tail and on head.next being accurate if the current
    // thread is first in queue.
    Node t = tail; // Read fields in reverse initialization order
    Node h = head;
    Node s;
    // 头节点就是尾节点,则队列没有其它等待节点
    // 队列存在节点,且
    //     头节点的next不存在,即此时有新节点插入队列,刚更新尾节点,还未来得及更新旧尾节点的next,那么队列中存在其它等待节点(新节点)
    //     或者存在但不是本线程,那么队列中有其它等待节点
    // 否则,不存在其它等待节点,因为头节点的next就是本线程节点,这是等待队列中的节点线程尝试获取锁的情况
    return h != t &&
        ((s = h.next) == null || s.thread != Thread.currentThread());
}

本方式是以公平竞争锁的方式实现的,公平的体现为:新线程在尝试获取锁之前,会先考虑当前是否已存在其它线程在等待获取锁,如果存在则直接放弃获取锁;如果不存在,才尝试获取锁;

Semaphore

构造函数

public Semaphore(int permits) {
    // 默认是非公平信号量,使用场景更多
    sync = new NonfairSync(permits);
}

public Semaphore(int permits, boolean fair) {
    sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

acquire

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

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

acquireUninterruptibly

public void acquireUninterruptibly() {
    sync.acquireShared(1);
}

public void acquireUninterruptibly(int permits) {
    // 校验入参
    if (permits < 0) throw new IllegalArgumentException();
    sync.acquireShared(permits);
}

tryAcquire

public boolean tryAcquire() {
    // 返回值不小于0则表示成功获取到锁
    return sync.nonfairTryAcquireShared(1) >= 0;
}

public boolean tryAcquire(int permits) {
    // 校验入参
    if (permits < 0) throw new IllegalArgumentException();
    // 返回值不小于0则表示成功获取到锁
    return sync.nonfairTryAcquireShared(permits) >= 0;
}

release

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

public void release(int permits) {
    // 校验入参
    if (permits < 0) throw new IllegalArgumentException();
    sync.releaseShared(permits);
}

其它方法

public int availablePermits() {
    return sync.getPermits();
}

public int drainPermits() {
    return sync.drainPermits();
}

protected void reducePermits(int reduction) {
    // 校验入参
    if (reduction < 0) throw new IllegalArgumentException();
    sync.reducePermits(reduction);
}

测试

Demo

class Demo {
    private int parties = 5;
    private Semaphore semaphore = new Semaphore(2);


    public static void main(String[] args) throws InterruptedException {
        Demo demo = new Demo();
        ExecutorService es = Executors.newFixedThreadPool(demo.parties);

        for (int i=0; i<demo.parties; i++) {
            es.execute(new SemaphoreTask(i, demo.semaphore));
        }
        es.shutdown();
    }


    private static class SemaphoreTask implements Runnable {

        private Semaphore semaphore;
        private int index;


        SemaphoreTask(int index, Semaphore semaphore) {
            this.semaphore = semaphore;
            this.index = index;
        }

        @Override
        public void run() {
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println("Thread:" + index + " waits to acquire semaphore");
                semaphore.acquire();
                System.out.println("Thread:" + index + " has acquired semaphore");

                TimeUnit.SECONDS.sleep(2);
                semaphore.release();
                System.out.println("Thread:" + index + " has released semaphore");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

测试结果

Thread:0 waits to acquire semaphore
Thread:0 has acquired semaphore
Thread:2 waits to acquire semaphore
Thread:2 has acquired semaphore
Thread:1 waits to acquire semaphore
Thread:3 waits to acquire semaphore
Thread:4 waits to acquire semaphore
Thread:0 has released semaphore
Thread:1 has acquired semaphore
Thread:2 has released semaphore
Thread:3 has acquired semaphore
Thread:1 has released semaphore
Thread:4 has acquired semaphore
Thread:3 has released semaphore
Thread:4 has released semaphore
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值