java.util.concurrent中的几种同步工具类(CyclicBarrier,CountDownLatch,Semaphore)

1.CyclicBarrier(栅栏)

1.1.简介

栅栏类似于闭锁,它能阻塞一组线程直到某个事件的发生。栅栏与闭锁的关键区别在于,所有的线程必须同时到达栅栏位置,才能继续执行。闭锁用于等待事件,而栅栏用于等待其他线程。

CyclicBarrier可以使一定数量的线程反复地在栅栏位置处汇集。当线程到达栅栏位置时将调用await方法,这个方法将阻塞直到所有线程都到达栅栏位置。如果所有线程都到达栅栏位置,那么栅栏将打开,此时所有的线程都将被释放,而栅栏将被重置以便下次使用。

1.2.用生活中的例子通过代码来演示

5个朋友约好下班一起玩英雄联盟开黑,分别是德玛西亚,卢锡安,寒冰,ez,扎克。但是5个哥们下班时间不一样,决定好一个时间一起上号搞。
在这里插入图片描述
大家约好到家就开游戏,必须珍惜生命,争分夺秒玩游戏。
在这里插入图片描述

我们用CyclicBarrier(栅栏)来模仿一下场景:

public class CyclicBarrierTest {

    /**
     * 英雄联盟玩家实体类 LeagueOfLegends
     */
    private static class LeagueOfLegends extends Thread {

        private static CyclicBarrier barrier = new CyclicBarrier(5);

        private String name;

        //下班时间
        private Long offWorkTime;

        public LeagueOfLegends(String name, Long time) {
            this.name = name;
            this.offWorkTime = time;
        }

        @Override
        public void run() {
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    System.out.println(name + ":我上号了");
                    try {
                        barrier.await();
                        System.out.println(name + ":开打开打");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, offWorkTime);
        }
    }

    public static void main(String[] args) {
        LeagueOfLegends dmxy = new LeagueOfLegends("德玛西亚", 2000L);
        LeagueOfLegends lxa = new LeagueOfLegends("卢锡安", 4000L);
        LeagueOfLegends hb = new LeagueOfLegends("寒冰", 6000L);
        LeagueOfLegends ez = new LeagueOfLegends("ez", 8000L);
        LeagueOfLegends zk = new LeagueOfLegends("扎克", 10000L);
        dmxy.start();
        lxa.start();
        hb.start();
        ez.start();
        zk.start();
    }
}

运行一下代码,感受一下,
在这里插入图片描述

2.CountDownLatch(闭锁)

2.1.介绍

ountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它们都存在于java.util.concurrent包下。CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务

2.2.在用生活中的例子通过代码来演示

好不容易,五个人都到到齐了,纷纷上号。要进行游戏,必须等队伍里所有人都点击准备完成,游戏才能开始。这种时候可以时候,我们可以使用闭锁来实现这种业务场景。
在这里插入图片描述

public class CountDownLatchTest {

    private static CountDownLatch countDownLatch = new CountDownLatch(5);

    public static class LeagueOfLegends extends Thread {

        private String name;

        private int time;

        public LeagueOfLegends(String name, int time) {
            this.name = name;
            this.time = time;
        }

        @Override
        public void run() {
            System.out.println(name + "我加载需要" + time + "ms");
            try {
                sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + "已加载完毕100%");
            countDownLatch.countDown();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("-----等待所有人准备-----");
        LeagueOfLegends dmxy = new LeagueOfLegends("德玛西亚", 5000);
        LeagueOfLegends lxa = new LeagueOfLegends("卢锡安", 4000);
        LeagueOfLegends hb = new LeagueOfLegends("寒冰", 3000);
        LeagueOfLegends ez = new LeagueOfLegends("ez", 2000);
        LeagueOfLegends zk = new LeagueOfLegends("扎克", 1000);
        dmxy.start();
        lxa.start();
        hb.start();
        ez.start();
        zk.start();

        countDownLatch.await();
        System.out.println("-----所有人准备好了-----");
        System.out.println("-----游戏开始-----");
        System.out.println( "-----欢迎来到召唤师峡谷-----");
    }
}

看看运行效果
在这里插入图片描述

3.Semaphore(信号量)

3.1.介绍

Semaphore(信号量):是一种计数器,用来保护一个或者多个共享资源的访问。如果线程要访问一个资源就必须先获得信号量。如果信号量内部计数器大于0,信号量减1,然后允许共享这个资源;否则,如果信号量的计数器等于0,信号量将会把线程置入休眠直至计数器大于0.当信号量使用完时,必须释放。

3.2 主要方法:

void acquire() :从信号量获取一个许可,如果无可用许可前将一直阻塞等待,
void acquire(int permits) :获取指定数目的许可,如果无可用许可前也将会一直阻塞等待
boolean tryAcquire():从信号量尝试获取一个许可,如果无可用许可,直接返回false,不会阻塞
boolean tryAcquire(int permits): 尝试获取指定数目的许可,如果无可用许可直接返回false
boolean tryAcquire(int permits, long timeout, TimeUnit unit): 在指定的时间内尝试从信号量中获取许可,如果在指定的时间内获取成功,返回true,否则返回false
void release(): 释放一个许可,别忘了在finally中使用,注意:多次调用该方法,会使信号量的许可数增加,达到动态扩展的效果,如:初始permits为1, 调用了两次release,最大许可会改变为2
int availablePermits(): 获取当前信号量可用的许可

3.3 在用生活中的例子通过代码来演示

有的时候,不仅这五位老哥去玩,时不时的拉克丝小姐姐也要来一起玩。这个时候有小姐姐一起玩游戏了,大家就一起抢位置了要和小姐姐一起玩。没能挤进队伍的老哥内心百感交集,欲说还休。
在这里插入图片描述

public class SemaphoreTest {


    private static class LeagueOfLegends extends Thread {
        private static Semaphore semaphore = new Semaphore(5);

        private String name;
        

        public LeagueOfLegends(String name) {
            this.name = name;
        }

        @Override
        public void run() {
                    if (semaphore.tryAcquire()) {
                        System.out.println(name + ":我进入游戏啦,可以和小姐姐玩了");
                    } else {
                        System.out.println(name + ":卧槽,队伍满了,我好想和小姐姐一起玩");
                    }

        }

        public static void main(String[] args) throws InterruptedException {
            LeagueOfLegends dmxy = new LeagueOfLegends("德玛西亚");
            LeagueOfLegends dbzg = new LeagueOfLegends("德邦总管");
            LeagueOfLegends rkss = new LeagueOfLegends("若克萨斯");
            LeagueOfLegends ez = new LeagueOfLegends("ez");
            LeagueOfLegends lks = new LeagueOfLegends("拉克丝");
            LeagueOfLegends ylzz = new LeagueOfLegends("影流之主");
            dmxy.start();
            dbzg.start();
            rkss.start();
            ez.start();
            lks.start();
            ylzz.start();

        }
    }
}

运行效果
在这里插入图片描述

https://www.cnblogs.com/null-qige/p/9337656.html 参考文献

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值