7、那些基于AQS的同步器

之前说过AQS 是所有同步器的基础,那么我们就来说说那些基于AQS的同步工具吧

1、Semaphore 信号量

Semaphore(信号量)是一个控制并发数量两的同步器(吐槽:这名字和功能有毛线关系啊),他的构造接受一个int 参数,代表着并发数,当并发数,超过这个数就去队列中排队吧(这和读写锁中 读锁不是异曲同工吗,只不过读锁无法设置共享的线程数)。原理很好理解的吧,下面看看用法:

 public static void main(String[] args) {

        Semaphore semaphore = new Semaphore(5);

        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                try {
                    String name = Thread.currentThread().getName();
                    System.out.println(name + " 我来上厕所了");
                    boolean b = semaphore.tryAcquire();
                    if (!b){
                        System.out.println(name + " 我没抢到坑位了");
                    }
                    System.out.println(name + " 我抢到一个坑,还剩" + semaphore.availablePermits() + "坑位");
                    Thread.sleep(3000);
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

这段程序 创建了一个信号量 控制并发数5个,启动六个线程取上厕所。相当于六个人去抢五个厕所啊!我们看看结果


image.png

2号线程开始没有抢到,被人用完了,才抢到的,要是没有用信号量控制,岂不是2号线程要在别人头上拉屎了吗?

综上:Semaphore 是和用于资源有限的共享情况,比如数据库连接池等。

2、CountDownLatch 计数器

CountDownLatch 是一个计数器,当计数器不到阈值(0)程序会一直等待。CountDownLatch 和Semaphore 提供了一个带有int参数的构造器。提供了一个countDown() (每次调用计数器减一)。他适合在多个任务需要相互协作的场景,比如 王者荣耀 需要五个人才可以开始游戏。我们可以设置一个数量为5的计数器,每一个人进入游戏就countDown 一次,当计数器为0的时候,游戏就可以开始啦。
下面看看用法:

 public static void main(String[] args) throws Exception {

        final CountDownLatch countDownLatch = new CountDownLatch(5);

        for (int i = 1; i < 6; i++){
            final int num = i;
            new Thread(() -> {

                System.out.println("我是第" + num +" 个玩家,我进入游戏啦。");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
            }).start();
        }
        //等待计数器到达阈值
        countDownLatch.await();
        System.out.println("终于有五个人了啊,开始游戏吧!");
    }

countDownLatch.await() 这个方法会一直等待计数器到达阈值,如果这个方法只有四个人进入游戏,那么这局游戏永远无法开始啦,不信你试试。

3、CyclicBarrier 回环栅栏

之前用游戏这个案例来说明CountDownLatch 的用法,但是我们发现一个很严重的问题,那就是游戏是要一直开始,每五个人就要开始一局的,那么计数器用一次岂不是用不了了? 别担心 我们还有CyclicBarrier 。
CyclicBarrier 在我看来就是一个可以无限使用的计数器,它只要每达到阈值就会重新开始,
下面看看用法吧

 public static void main(String[] args) throws Exception {

        String[] arr = {"小明", "小陈", "小牛", "大神", "菜鸡"};
      //CyclicBarrier 构造器 接受两个参数 1、阈值 2、到达阈值后的操作(为空则什么都不做)
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> {
            System.out.println("有五个玩家加入游戏,游戏开始!!!!!!!!");
        });

        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                try {
                    Thread.sleep(new Random().nextInt(10000));
                    System.out.println(Thread.currentThread().getName() + "加入排位,总共有" + (cyclicBarrier.getNumberWaiting() + 1) + "玩家在等待");
                  //回环等待,等到阈值
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, arr[i / 5]);
            thread.start();
        }
    }

看看结果:


image.png

从结果上看 每五个人进入游戏,CyclicBarrier 就只执行一次 事先内置的任务。
使用上他和CountDownLatch 还是很有很大差别的。CountDownLatch是计算器,只有煮线程在等待计数器结果,其他线程处理完任务就完事了,而CyclicBarrier 是一个屏障,所有的线程遇到屏障都会停下来,等到集齐突破屏障的条件(例子中是五人进入游戏) 在一起处理,并且可以触发事先预留的处理事件(简直就像是集齐七颗龙珠召唤神龙一样 有木有!)。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,132评论 6 523
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,457评论 3 404
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,411评论 0 368
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,147评论 1 301
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,145评论 6 400
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,611评论 1 315
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,962评论 3 429
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,948评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,479评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,514评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,640评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,228评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,973评论 3 340
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,402评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,551评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,210评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,714评论 2 366

推荐阅读更多精彩内容

  • 本文是我自己在秋招复习时的读书笔记,整理的知识点,也是为了防止忘记,尊重劳动成果,转载注明出处哦!如果你也喜欢,那...
    波波波先森阅读 11,284评论 4 56
  • Java继承关系初始化顺序 父类的静态变量-->父类的静态代码块-->子类的静态变量-->子类的静态代码快-->父...
    第六象限阅读 2,164评论 0 9
  • 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,Cycl...
    Pure_Dream阅读 1,435评论 0 3
  • 分享是一种感性的生活,分享是一份洒脱的情怀,分享是一段美妙的际遇,分享是一生最好的安排。 昨晚读...
    tensilecam阅读 475评论 0 0
  • 我捡过一只跛脚的小猫咪 巴掌大 它残缺的身体 以及 哀恸的叫声触动了我 我收养了它 三个月 他...
    c老镇阅读 172评论 0 2