并发工具类 Semaphore

2017-10-15  本文已影响0人  少博先生

上篇介绍了内部使用AQS的并发工具类CountDownLatch,接下来我要介绍的并发工具类Semaphore内部同样使用了AQS。

简介

信号量(Semaphore),有时被称为信号灯,一个控制访问多个共享资源的计数器,负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。
从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。拿到信号量的线程可以进入代码,否则就等待。通过acquire()和release()获取和释放访问许可。

继续拿上篇中的吃火锅案例,假设这家小肥羊的洗手间比较高级,洗手间一共有五个坑位,洗手间门有一个信号灯,就跟火车上那个相似,但是火车上的高级,可以显示洗手间当前的可用坑位个数。那么这个五个坑位就是公共资源,信号灯就是Semaphore,要用洗手间的顾客就是线程。

构造方法
构造方法

如果以公平方式执行,则线程将会按到达的顺序(FIFO)执行,如果是非公平,则可以后请求的有可能排在队列的头部。

acquire()获取资源
acquire()

还是老套路,调用AQS的acquireSharedInterruptibly(int arg)

AQS的acquireSharedInterruptibly(int arg)

公平锁和非公平锁的获取资源是不一样,先看公平锁的:

公平锁的tryAcquireShared(int arg)

非公平锁的:

公平锁的nonfairTryAcquireShared(int arg)
release() 释放资源
release() AQS的releaseShared(int arg)

公平锁和非公平锁的获取资源不一样,但释放资源是一样的。

tryReleaseShared(int releases)

案例

public class AA implements Runnable {
    private Semaphore semaphore;
    private int id;
    public AA(Semaphore semaphore, int id) {
        this.semaphore = semaphore;
        this.id = id;
    }

    @Override
    public void run() {
        try {
            //获取坑位
            semaphore.acquire();
            System.out.println("第 " + id  + " 个人正在使用");
            Thread.sleep((long)(Math.random() * 1000));
            //使用完后,出洗手间,释放坑位
            semaphore.release();
            System.out.println("第 " + id + " 个人用完了");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class GoWC {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(5);

        ExecutorService se = Executors.newCachedThreadPool();
        se.submit(new AA(semaphore,1));
        se.submit(new AA(semaphore,2));
        se.submit(new AA(semaphore,3));
        se.submit(new AA(semaphore,4));
        se.submit(new AA(semaphore,5));
        se.submit(new AA(semaphore,6));
        se.submit(new AA(semaphore,7));
        se.submit(new AA(semaphore,8));
        se.submit(new AA(semaphore,9));
        se.submit(new AA(semaphore,10));
        se.shutdown();
    }
}

运行结果:

对于这个结果,感觉有点不太对,比如第5个人释放后,第6个人使用是没问题的,但为什么第7个人也是正在使用???这时同时存在6个线程一块执行,不知道哪写错了。。哪位同学看出问题了,望指出,3Q!

总结

本篇主要介绍了基于AQS的并发工具类Semaphore,起一个信号灯的作用,有公平模式和非公平模式之分,获取公共资源使用acquire,公平模式下的acquire比非公平模式下的acquire多了检查当前线程是否在队列最前端这一步骤,释放资源使用release,公平模式和非公平模式一致。

上一篇 下一篇

猜你喜欢

热点阅读