一个关于多线程协作的题目经常会出现在大厂的面试中:有三个线程分别打印A、B、C,请让这三个线程按顺序打印出ABC20次。
我们知道,线程调度机制是非确定性的,如果不加上额外的并发控制,直接启动三个线程,那么这几个线程的执行顺序是不确定的,打印出来的字符也不一定是按照ABC这样的顺序来显示。同时,题目不光要求按顺序打印出ABC,而且还要打印20次,也就是这样的形式:ABCABCABC...,当然,打印30次或者100次什么的,代码基本上一样,修改一下循环的次数即可。
实现这样的功能有很多方法,我们使用一种简洁方便的方式来完成,同时,为了加深印象和理解,我们尝试采用层层递进的方式来进行讲解,也就是:
启动三个线程,打印出ABC,但无序,可能是BCA,或者CBA等等。
启动三个线程,按照顺序打印出ABC,要确定每次运行都按这个顺序打印。
启用三个线程,按照顺序打印出ABC,不光要按照顺序打印,而且要连续打印20次,也就是ABCABC...这样的形式。
一、打印字符ABC,但无序
这个比较简单,三个线程各打印A、B、C,然后启动这些线程即可,当然,打印出来的字符就是没有顺序的了。代码如下:
package com.sample.interview.multithread;
// 三个线程打印字符ABC,但顺序不确定
public class PrintRandomly {
public static void main(String[] args) {
Thread threadA = new Thread(()-> System.out.print("A"));
Thread threadB = new Thread(()-> System.out.print("B"));
Thread threadC = new Thread(()-> System.out.print("C"));
threadA.start();
threadB.start();
threadC.start();
}
}
二、按顺序打印字符ABC
按顺序打印字符ABC,那我们就得控制这三个线程的执行顺序,线程A先执行,接下来是线程B,最后是线程C。针对类似的并发编程场景,Java提供了一个非常方便实用的类Semaphore,也就是信号量,可以将它看作一个“许可证”,通过它可以实现多线程对于公共资源的并发访问控制,一个线程在获取资源时需要先取得一个许可,否则会阻塞,资源使用完成后,再把许可放回去。
<