Java并发——信号量Semaphore

简述

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

实现原理

Semaphore中管理着一组虚拟的许可(permit),许可的初始数量可通过构造函数来指定。在执行操作时需要首先获得许可(只要还有剩余的许可),并在使用以后释放许可。如果没有许可,那么acquire方法将阻塞直到有许可(或者直到被中断或者操作超时),当执行完业务通过release方法将许可归还,以便其他线程能够获得许可继续执行

构造方法


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

Semaphore内部基于sync实现,参数permits表示许可证数量,参数fair表示是否采取公平策略

公平策略

sync继承AQS,只需要重写其模板中的方法即可,acquire方法如下:


    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    
    /**
     * AQS共享式获取同步状态模板方法(能响应中断)
     */
    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();
            // 计算acquire()之后,剩余的信号量许可数
            int remaining = available - acquires;
            // CAS设置信号量许可
            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;
        }
    }
复制代码

公平与非公平区别在于公平策略会调用hasQueuedPredecessors()方法判断线程所关联的节点是否在队列头位置

释放


    public void release() {
        sync.releaseShared(1);
    }
    
    /**
     * AQS共享式释放同步状态模板方法
     */
    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");
            // CAS设置新许可数    
            if (compareAndSetState(current, next))
                return true;
        }
    }
复制代码

示例


public class SemaphoreTest {
       
    public static void main(String[] args) {
        final Semaphore semaphore = new Semaphore(3);
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                     System.out.println(Thread.currentThread().getName() + "进入车库");
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        semaphore.release();
                        System.out.println(Thread.currentThread().getName() + "出车库");
                    }
                }
            }).start();
        }
    }
      
}
复制代码

感谢

《java并发编程的艺术》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值