题目:3个线程循环打印ABC,其中A打印3次,B打印2次,C打印1次
网络上给的答案多数是使用wait()、notifyAll()来处理,同时在线程中使用相关ABC字符的判断来运行代码。但是这类方式方法扩展性和可读性降低了很多。
题意:
- 三个线程 --- 假设题目想增加多个线程打印怎么办?
- 循环打印 --- 假设题目期待不使用循环了而使用其他方式怎么办?
- 打印动作ABC --- 假设题目打印规则不再是单纯的打印字符这么简单怎么办?
这套连招平时在工作中和产品经理讨论需求时恐怕没有少做吧,在产品经理给的需求中,伴随这业务增长个别需求总是会不断变更,所以需要更高的扩展性代码才能满足日益增加的需求。
当初看到这个题目的时候,脑袋里的第一想法不是使用wait、notifyAll来完成。而是想的是数组+LockSupport.park()来完成。
问题拆解
1.定义执行动作接口
//执行动作接口
public interface ExecuteAction {
void action();
}
2.任务调度类
public class ActionSchedule extends Thread{
ArrayList<Thread> list = new ArrayList<>(); //任务列表
public void addAction(ExecuteAction action){
list.add(new Thread(()->{
while (true){ //循环执行action方法,同时先调用park方法阻塞自己线程
LockSupport.park();
action.action();
LockSupport.unpark(this); //唤醒任务调度线程
}
}));
}
@Override
public void run() {
try {
while (true){
for (Thread thread : list) {
LockSupport.unpark(thread); //唤醒任务线程,使任务线程继续执行
LockSupport.park();
}
Thread.sleep(1000);
System.out.println("========");
}
}catch (Exception e){
e.printStackTrace();
}
}
public void execute() throws Exception{
if(list.size() == 0) throw new Exception("list can't be empty");
list.forEach(thread -> thread.start());
this.start();
}
}
public static void main(String[] args) throws Exception{
ActionSchedule actionSchedule = new ActionSchedule();
actionSchedule.addAction(()-> System.out.print("A"));
actionSchedule.addAction(()-> System.out.print("B"));
actionSchedule.addAction(()-> System.out.print("C"));
actionSchedule.execute();
}
整个流程大致是:action接口功能就是打印ABC字符,放入ActionSchedule list中,在执行过程中首先启动list中的线程,通过schedule与list中Thread相互调用park方法达到循环打印ABCABC的效果
网友评论