最近几次的面试让我感觉到飘了,今天主动找到正在看肥皂剧的女友,让她去拿那个所谓的面试题全集过来,号称无所不知,无所不会
女友:打扰我看帅哥,我很生气,后果很严重。。。来,今天说点多线程的辅助工具类。不过不会简单的说说用法,要结合使用场景给我详细说说
你们每天早上是不是都要开晨会是吧,那么是不是要所有的人都到了才能开始,那么使用程序怎么控制这个呢?
我:嗯,假装沉思一会。。。这个我有两种实现方法,一种是使用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();
}
}
}
其实这个工具类不是很常用,我就没用过,但是理解了和面试官吹吹牛也是不错的