• Semaphore实战


    简介


    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个用户同时在线。

    image.png

    注意:上面举出的这个案例,出个思考题:线程池是否可以实现呢?

     

    • 模拟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,会通知主线程退出等待继续往下执行。执行结果如下图所示。

    image.png

    有没有发现Semaphore用法可以模拟CountDownLatch,另外Semaphore通过调用acquire,release方法,还可以实现CyclicBarrier功能!我们不举例了。

     

     

    实现原理


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

     

     

    总结


    今天我们介绍了Semaphore,整理出来希望能对你有帮助,写的比不全,同时还有许多需要修正的地方,希望亲们加以指正和点评,喜欢的请点赞加关注哦。点关注,不迷路,我是【叫练公众号,微信号【jiaolian123abc】边叫边练。

  • 相关阅读:
    java多线程
    java垃圾回收
    java研发常见问题总结 1
    js获取时间加多山天和时间戳转换成日期
    php时间选择器亲测可以自己修改
    html5时间选择器
    php生成员工编号,产品编号
    桌面远程链接
    SQL 左外连接查询 将右表中的多行变为左表的一列或多列
    PHPMailer发匿名邮件及Extension missing: openssl的解决
  • 原文地址:https://www.cnblogs.com/jiaolian/p/14481549.html
Copyright © 2020-2023  润新知