面试题:三个线程轮流打印A ,B,C
面试介绍说明
当时是2022 年3月 在深圳面试的一家公司。由于疫情比较严重,是电话面试。前面的八股文还比较熟悉,和面试官沟通的还不错。后面聊到多线程,说让实现 三个线程轮流打印 ABC。我当时听,有点懵,之前只是复习了用wait/notify 来实现生产消费者模型。只有两个主体,现在 是三个,瞬间没有了主意,当时也是 和面试官 纠缠了一会,但面试官很较真,他说 他正打开 idea,让我说,他来敲代码。于是 GG…现在又重新学习下多线程,自己突然有了思路,然后就写了下,发现居然没有毛病。特此记录下。
思考方案
还是建立在生产者和消费者模型下。 只是多个了一个主体。执行run 方法的时候,加个判断即可。
流程如下:
代码实现
Print 打印基类
/**
* @author :echo_黄诗
* @description:打印基类
* @date :2023/2/3 17:03
*/
public class Print extends Thread{
protected Str str;
protected Object lock;
public Print(Str str,Object lock) {
this.str = str;
this.lock=lock;
}
}
APrint 打印字符A 线程
/**
* @author :echo_黄诗
* @description:打印字符A 线程
* @date :2023/2/3 16:59
*/
public class APrint extends Print{
public APrint(Str str, Object lock) {
super(str, lock);
}
@Override
public void run() {
//获取锁
synchronized (lock){
//当前线程 状态正常的
while (!Thread.currentThread().isInterrupted()){
if (str.getString().equals(PrintConstant.C)){
System.out.println(PrintConstant.A);
str.setString(PrintConstant.A);
}else {
lock.notifyAll();
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
CPrint 打印字符C 线程
/**
* @author :echo_黄诗
* @description:打印字符C 线程
* @date :2023/2/3 17:05
*/
public class CPrint extends Print {
public CPrint(Str str, Object lock) {
super(str, lock);
}
@Override
public void run() {
//获取锁
synchronized (lock){
//当前线程 状态正常的
while (!Thread.currentThread().isInterrupted()){
if (str.getString().equals(PrintConstant.B)){
System.out.println(PrintConstant.C);
str.setString(PrintConstant.C);
}else {
lock.notifyAll();
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
PrintConstant 常量类
/**
* @author :echo_黄诗
* @description:常量类
* @date :2023/2/3 18:11
*/
public class PrintConstant {
public static final String A="A";
public static final String B="B";
public static final String C="C";
}
Str
/**
* @author :echo_黄诗
* @description:信号量类
* @date :2023/2/3 17:07
*/
public class Str {
private String string;
public Str(String string) {
this.string = string;
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
}
Run 启动类
/**
* @author :echo_黄诗
* @description:测试类
* @date :2023/2/3 17:06
*/
public class Run {
public static void main(String[] args) {
Object lock=new Object();
//str 的值可以赋值
Str str=new Str(PrintConstant.C);
APrint aPrint=new APrint(str,lock);
BPrint bPrint=new BPrint(str,lock);
CPrint cPrint=new CPrint(str,lock);
aPrint.start();
bPrint.start();
cPrint.start();
}
}
测试结果
三个线程 的启动顺序没有要求。
采用Lock和Condition实现
代码展示
package cn.com.echo.demo.lock.condition;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author :echo_黄诗
* @description:实现轮流打印
* @date :2023/2/6 16:09
*/
public class Run {
private volatile static int nextPrintWho=1;
private static ReentrantLock lock=new ReentrantLock();
final private static Condition conditionA=lock.newCondition();
final private static Condition conditionB=lock.newCondition();
final private static Condition conditionC=lock.newCondition();
public static void main(String[] args) {
Thread threadA=new Thread(){
@Override
public void run() {
try {
lock.lock();
while (nextPrintWho!=1){
conditionA.await();
}
/* for (int i=0;i<3;i++){
//System.out.println("ThreadA "+(i+1));
}*/
System.out.println("A");
nextPrintWho=2;
conditionB.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
};
Thread threadB=new Thread(){
@Override
public void run() {
try {
lock.lock();
while (nextPrintWho!=2){
conditionB.await();
}
/* for (int i=0;i<3;i++){
//System.out.println("ThreadB "+(i+1));
System.out.println("B");
} */
System.out.println("B");
nextPrintWho=3;
conditionC.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
};
Thread threadC=new Thread(){
@Override
public void run() {
try {
lock.lock();
while (nextPrintWho!=3){
conditionC.await();
}
/* for (int i=0;i<3;i++){
//System.out.println("ThreadC "+(i+1));
System.out.println("C");
}*/
System.out.println("C");
nextPrintWho=1;
conditionA.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
};
Thread[]threadsA=new Thread[50];
Thread[]threadsB=new Thread[50];
Thread[]threadsC=new Thread[50];
for (int i=0;i<50;i++){
threadsA[i]=new Thread(threadA);
threadsB[i]=new Thread(threadB);
threadsC[i]=new Thread(threadC);
threadsA[i].start();
threadsB[i].start();
threadsC[i].start();
}
}
}
总结
notify/wait 和lock/condition 这两种实现的思路 是一样的。大伙还有其他的思路吗?