简介


Semaphore信号量计数器。和CountDownLatch,CyclicBarrier相似,是多线程合作的工具类,绝对于join,wait,notify办法应用起来简略高效。上面咱们次要看看它的用法吧!

实战


  • 限流。限度线程的并发数。

比方在一个零碎中同时只能保障5个用户同时在线。

import java.util.concurrent.Semaphore;/** * @author :jiaolian * @date :Created in 2021-03-04 11:13 * @description:Semaphore限流 * @modified By: * 公众号:叫练 */public class LimitCurrnet {    public static void main(String[] args) throws InterruptedException {        //定义20个线程,每次最多只能执行5个线程;        Semaphore semaphore = new Semaphore(5);        for (int i=0; i<20; i++) {            new Thread(()->{                try {                    //获取凭证                    semaphore.acquire();                    System.out.println(Thread.currentThread().getName()+"登录胜利");                    Thread.sleep(2000);                    //开释凭证                    semaphore.release();                    System.out.println(Thread.currentThread().getName()+"用户退出");                } catch (InterruptedException e) {                    e.printStackTrace();                }            }).start();        }    }}

如上代码所示:咱们定义了20个用户同时拜访零碎,Semaphore参数是5,示意同时只能有5个用户能够获取凭证,其余用户必须期待直到有在线用户退出。调用semaphore.acquire()示意获取凭证,此时凭证数会减一,调用semaphore.release()示意开释凭证,凭证数会加一,如果零碎中有期待的用户,操作此办法会告诉期待的一个用户获取凭证胜利,执行登录操作。最初打印局部后果如下:证实零碎最多能放弃5个用户同时在线。

留神:下面举出的这个案例,出个思考题:线程池是否能够实现呢?

  • 模仿CyclicBarrier,CountDownLatch重用!

Semaphore能够轻松实现CountDownLatch计数器,CyclicBarrier回环屏障,还记得CountDownLatch用法么?它是个计数器,能够帮咱们统计线程执行工夫,罕用来测试多线程高并发执行接口效率,咱们上面用Semaphore模仿多线程主线程期待子线程执行结束再返回。

import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;/** * @author :jiaolian * @date :Created in 2021-03-01 21:04 * @description:信号量测试 * @modified By: * 公众号:叫练 */public class SemaphoreTest {    //定义线程数量;    private static final int THREAD_COUNT = 2;    //初始化信号量为0,默认是非偏心锁    private static Semaphore semaphore = new Semaphore(0,false);    private static ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);    public static void main(String[] args) throws InterruptedException {        for (int i=0; i<THREAD_COUNT; i++) {            executorService.submit(()->{                try {                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println(Thread.currentThread().getName()+"执行");                semaphore.release();            });        }        //获取2个信号量        semaphore.acquire(2);        System.out.println("主线程执行结束");        executorService.shutdown();    }}

如上代码所示:咱们定义了Semaphore初始化信号量为0,默认是非偏心锁,在主线程中用线程池提交2个线程,主线程调用semaphore.acquire(2)示意须要获取两个信号量,但此时初始化信号量为0,此时AQS中的state会是0-2=-2,state值小于0,所以主线程执行这句话会阻塞将其退出AQS同步队列,线程池两个线程期待2秒后会调用semaphore.release()开释2个信号量,此时AQS中的state会自增到0,会告诉主线程退出期待持续往下执行。执行后果如下图所示。

有没有发现Semaphore用法能够模仿CountDownLatch,另外Semaphore通过调用acquire,release办法,还能够实现CyclicBarrier性能!咱们不举例了。

实现原理


  • 相同点:实质上都是计数器,底层是依赖AQS操作state实现。
  • 异同点:CountDownLatch是共享锁实现,CyclicBarrier是独占锁实现,CountDownLatch通过调用countDown递加计数器只能应用一次,而CyclicBarrier通过调用await递加计数器能够达到“回环”反复的成果。Semaphore也是共享锁实现,通过调用release计数器是递增的,通过设置信号量能够实现CyclicBarrier,CountDownLatch性能。

总结


明天咱们介绍了Semaphore,整理出来心愿能对你有帮忙,写的比不全,同时还有许多须要修改的中央,心愿亲们加以斧正和点评,喜爱的请点赞加关注哦。点关注,不迷路,我是【叫练公众号,微信号【jiaolian123abc】边叫边练。