一道题检测多线程基本功!(顺序打印ABC)
初阶
题目内容:
有三个线程,线程名称分别为:A,B,C。
要求:使三个线程同时启动,并按顺序打印A,B,C。
注:有的人看到这个题目,直接就是创建三个线程,然后直接调用对应的star()方法,这当然是个坑啦。这里我们可以想到join方法,让A线程跑完,再跑B,B线程跑完再跑C。
public class printABC {
public static void main(String[] args) {
Thread a = new Thread(()->{
System.out.print(Thread.currentThread().getName());
},"A");
Thread b = new Thread(()->{
try {
a.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(Thread.currentThread().getName());
},"B");
Thread c = new Thread(()->{
try {
b.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(Thread.currentThread().getName());
},"C");
a.start();
b.start();
c.start();
}
}
看上去是不是超简单?这道题进阶一下再看看。
进阶
题目内容:
还是有三个线程,分别打印A,B,C。
要求:按顺序打印ABC,打印10次,同时启动这三个线程。注意:不要用sleep等变相启动线程的方法。
分析:
- 连续打印10次,并且需要有顺序,那么就可以联想到线程间通信来解决这个问题。
- 每个线程分别对应打印A、B、C,那么就可以使用数组将他们三个保存起来,称为共享资源,匹配到了,则输出。
- 利用数组的特性,那么我们就可以使用对应下标去寻找对应数组中的字母,并且可以实现多次循环,按顺序进行。
- 由此看来,三个线程执行的都是相同功能,可以单独写一个类来封装,使得代码简便。
public class SequencePrint {
public static void main(String[] args) {
Thread a = new Thread(new Task("A"));
Thread b = new Thread(new Task("B"));
Thread c = new Thread(new Task("C"));
c.start();
b.start();
a.start();
}
private static class Task implements Runnable{
//每个线程有唯一标识字段
private String content;
//顺序打印的内容:可以循环打印
private static String[] ARR = {"A","B","C"};
private static int INDEX;//从数组哪个索引打印
public Task(String content){
this.content = content;
}
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
synchronized (ARR) {//三个线程使用同一把锁
//从数组索引位置打印,如果当前线程要打印的内容不一致,释放对象锁等待
//while循环防止,释放锁之后,该线程再次抢占并向下执行。
while (!content.equals(ARR[INDEX])) {
ARR.wait();
}
//如果数组要打印的内容和当前线程要打印的一致,
//就打印,并把数组索引切换到一个位置,通知其他线程
System.out.print(content);
if (INDEX == ARR.length - 1) {
System.out.println();
}
//控制下标始终在0,1,2里面循环
INDEX = (INDEX + 1) % ARR.length;
//该线程执行完了,唤醒下一个线程向下执行
ARR.notifyAll();
}
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}