当前位置: 首页>前端>正文

女友面试我java多线程(四)

最近几次的面试让我感觉到飘了,今天主动找到正在看肥皂剧的女友,让她去拿那个所谓的面试题全集过来,号称无所不知,无所不会

女友:打扰我看帅哥,我很生气,后果很严重。。。来,今天说点多线程的辅助工具类。不过不会简单的说说用法,要结合使用场景给我详细说说

你们每天早上是不是都要开晨会是吧,那么是不是要所有的人都到了才能开始,那么使用程序怎么控制这个呢?

我:嗯,假装沉思一会。。。这个我有两种实现方法,一种是使用join,不过这种方法稍微复杂而且前面讲过,今天我就说说第二种方法,使用countDownLatch

public class CountDownLatchTest {

    public static void main(String[] args) {
        CountDownLatchTest countDownLatchTest = new CountDownLatchTest();
        System.out.println("组长:开晨会了,都快来");
        countDownLatchTest.array();
        System.out.println("组长:好了,都到了,我们开始吧。。。");
    }

    public void array(){
        List<String> personList = Arrays.asList("张三","李四","王二");
        CountDownLatch countDownLatch = new CountDownLatch(personList.size());//设置限制的数量

        for (String str:personList) {
            new Thread(()->{
                System.out.println(str + " 来了");
                countDownLatch.countDown();//每执行完一个数量就将数量减一
            }).start();
        }

        try {
            countDownLatch.await();//在这里阻塞 直到countDownLatch数量减完才会通过
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("都到了。。。");
    }
}

从上面可以看出来,CountDownLatch是用来控制达到多少数量之后才执行

女友:嗯嗯,还行,不过这样好像简单了点,你对CyclicBarrier这个工具类了解吗?它适合用在什么场景?

我:嘿,有点道行了啊。这个工具类和上面的countdownlatch稍微有点相似,但是是两个不同概念,

  • **CountDownLatch的概念是多线程执行的任务都执行完了之后才继续执行后面的逻辑,强调的是上面的所有任务都执行完了再执行其他的逻辑 **
  • CyclicBarrier的概念是先让多个线程到某一个点集合,等到集合到达某一数值了,放行这些线程继续执行

使用一个现实生活中非常常见的例子:下班后赶班车

public class CountDownLatchTest {

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(30, ()-> System.out.println("好了,人满发车"));
        for (int i=0;i<100;i++) {
            new Thread(()-> {
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

执行后会发现只会发三辆车子,还有十个人因为无法满车就一直在公司走不了咯。。。这样应该更能理解这两个辅助类的差别了吧。。

女友:不错啊,这个场景很形象了,我们继续,说会说semaphore这个工具类吧。

我:这个类叫做信号量,他可以接受一个参数,标识同时只有这些线程可以自行,相当于是一个限流的功能,当然由于限流,肯定就会有线程阻塞的存在,所以他也有公平和非公平的设置。就比如说你去公司食堂吃饭,由于到了饭点一下子会有上千人涌入食堂,但是窗口也就那么多,这就是限流。而公平就是被限制的流自动去排队等候,非公平呢就是一窝蜂的往里面挤,可能后面来的同事幸运一点能够先拿到饭。

public class CountDownLatchTest {

    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2);
        List<String> list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        for(String str : list) {
            new Thread(()->{
                try {
                    semaphore.acquire();
                    System.out.println(str +" 吃上了饭");

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

}

可以发现,由于限流只能让两个人吃上饭,所以第三个人来了也acquire不到了,就需要在哪里等着了

女友:可以,我都理解了。还有一个辅助类Phaser,你使用过吗?用过的话适用于什么场景呢?

我:你还上瘾了?这个类当然用过(我是没用过,哈哈),它是将上面两个辅助类的功能集成起来了,可以这样理解,有很多的线程,当某些线程到达某个阶段继续进行下一个阶段。直接使用一个案例来说应该会更好理解:领奖

情景:
1. 当所有中奖成员到达颁奖典礼会场后,开始颁奖典礼
2. 进行颁奖仪式
3. 主持人进行最终总结

代码如下:

public class CountDownLatchTest {

    //颁奖阶段控制类
    //该类重写了流程控制
    static class AwardPhaser extends Phaser {
        @Override
        protected boolean onAdvance(int phase, int registeredParties) {
            switch (phase){
                case 0:
                    System.out.println("人员全部到场" + registeredParties);
                    return false;
                case 1:
                    System.out.println("颁奖结束" + registeredParties);
                    return false;
                case 2:
                    System.out.println("主持人进行最终总结" +  registeredParties);
                    return true;
                default:return true;
            }
        }
    }

    static AwardPhaser phaser = new AwardPhaser();

    static Random random = new Random();
    public static void main(String[] args) {
        CountDownLatchTest countDownLatchTest = new CountDownLatchTest();
        List<String> personList = Arrays.asList("张三","李四","王二");
        phaser.bulkRegister(personList.size()+1);
        for (String str: personList) {
            new Thread(()->{
                countDownLatchTest.arrive(str);
                countDownLatchTest.award(str);
                countDownLatchTest.speak(str);
            }).start();
        }

        new Thread(()->{
            countDownLatchTest.arrive("主持人");
            countDownLatchTest.award("主持人");
            countDownLatchTest.speak("主持人");
        }).start();

    }

    //到达会场
    public void arrive(String name){
        try {
            Thread.sleep(random.nextInt(1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + " 到了");
        phaser.arriveAndAwaitAdvance();
    }

    //进行颁奖
    public void award(String name){
        try {
            Thread.sleep(random.nextInt(1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + " 颁奖结束");
        phaser.arriveAndAwaitAdvance();
    }

    //颁奖总结
    public void speak(String name){
        try {
            Thread.sleep(random.nextInt(1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if ("主持人".equals(name)) {
            System.out.println(name + " 进行颁奖总结");
            phaser.arriveAndAwaitAdvance();
        } else {
            phaser.arriveAndDeregister();
        }
    }
}

其实这个工具类不是很常用,我就没用过,但是理解了和面试官吹吹牛也是不错的


https://www.xamrdz.com/web/2ag1994627.html

相关文章: