本文内容
本文将从一个现实例子来实际说明线程调度方法wait,notify和notifyAll的使用。
工厂中任务的领受和执行
某工厂执行这样的机制:当生产任务下达到车间时会统一放在一个地方,由工人们来取活。
工人取活如此执行:一个工人手头只能有一个活,如果没做完不能做下一个,如果做完了则可以到公共的地方去取一个;如果没有活可取则闲着直到来活为止。
本文就是讲述怎样使用线程的调度三方法wait,notify和notifyAll来实现这一现实活动的。
任务类Task-它用来实现一个”活”,其中关键的成员是完成需消耗的工时数manHour和已经完成的工时数completed
public class Task implements Comparable {
private String id;
private String name;
// 完成需消耗的工时数
private int manHour;
// 已经完成的工时数
private int completed;
// 优先级
private int priority;
// 接受任务者
private Worker worker;
public Task(String name, int manHour) {
this(name, manHour, 0);
}
public Task(String name, int manHour, int priority) {
id = IdUtil.generateId();
this.name = name;
this.manHour = manHour;
this.priority = priority;
this.completed = 0;
}
// 任务是否完成
public boolean isCompleted() {
return completed >= manHour;
}
// 添加完成度
public void addCompleted(int n) {
completed += n;
if (isCompleted()) {
completed = manHour;
if (worker != null) {
System.out.println("任务"+this+"处理完毕!");
}
}
}
public int compareTo(Object obj) {
Task another = (Task) obj;
return (another.priority) - this.priority;
}
public String toString() {
return "任务名:" + name + " 工人名:" + worker.getName() + " 完成度:" + completed
* 100 / manHour + "%";
}
public String getCompletedRatio() {
return " 完成度:" + completed * 100 / manHour + "%";
}
...getter/setter方法省略..
}
任务库类TaskLibrary
这个类对应现实中的取活的地方,每个活Task放在这个类的成员tasks中,有两个方法来添加单个任务和多个任务,还有一个fetchTask方法来供工人领受任务.
public class TaskLibrary {
private List<Task> tasks;
public TaskLibrary() {
tasks = new LinkedList<Task>();
}
// 添加单个任务
public synchronized void addTask(Task task) {
tasks.add(task);
notifyAll();
}
// 添加多个任务
public synchronized void addTasks(List<Task> moreTasks) {
tasks.addAll(moreTasks);
notifyAll();
}
public int getTaskSize() {
return tasks.size();
}
// 工人领受任务
public synchronized Task fetchTask(Worker worker) {
while (tasks.size() == 0) {
try {
System.out.println("任务告罄");
System.out.println("工人:" + worker.getName() + "进入闲置状态");
wait();
} catch (InterruptedException ex1) {
ex1.printStackTrace();
}
}
Task task = tasks.get(0);
System.out.println("工人:" + worker.getName() + "取得任务:" + task.getName());
tasks.remove(task);
return task;
}
}
工人类Worker
public class Worker implements Runnable {
private String id;
private String name;
private Task currTask;
private TaskLibrary taskLibrary;
// 工作速度
private int speed;
public Worker(String name, int speed, TaskLibrary taskLibrary) {
id = IdUtil.generateId();
this.currTask = null;
this.name = name;
this.speed = speed;
this.taskLibrary = taskLibrary;
doWork();
}
// 开始干活
public void doWork() {
Thread thread = new Thread(this);
thread.start();
}
// 真正干活
public void run() {
while (true) {
if (currTask == null || currTask.isCompleted()) {
currTask = taskLibrary.fetchTask(this);
currTask.setWorker(this);
}
try {
Thread.sleep(1000);
System.out.println("正在处理的任务" + currTask + " 完成度"
+ currTask.getCompletedRatio() + "个.");
currTask.addCompleted(speed);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
。。。
}
运行代码
TaskLibrary taskLibrary=new TaskLibrary();
taskLibrary.addTask(new Task("培训",8));
List<Task> moreTasks=new LinkedList<Task>();
moreTasks.add(new Task("锻造",4));
moreTasks.add(new Task("打磨",5));
moreTasks.add(new Task("车阶梯",6));
moreTasks.add(new Task("热处理",7));
moreTasks.add(new Task("去皮",8));
moreTasks.add(new Task("镗孔",60));
moreTasks.add(new Task("钻孔",10));
moreTasks.add(new Task("拉槽",11));
taskLibrary.addTasks(moreTasks);
Worker worker01=new Worker("王进喜",1,taskLibrary);
Worker worker02=new Worker("时传详",2,taskLibrary);
Worker worker03=new Worker("张秉贵",3,taskLibrary);
Worker worker04=new Worker("徐虎",3,taskLibrary);
taskLibrary.addTask(new Task("铸造",8));
sleep(1);
taskLibrary.addTask(new Task("校验",9));
sleep(2);
taskLibrary.addTask(new Task("内务",10));
sleep(3);
运行情况分析
一开始先初始化任务库,然后进行给任务库中添加任务,初始化工人实例时会把任务库实例的地址传入,工人实例初始化完毕后会调用doWork函数去任务库取任务开始做,这会进入TaskLibrary类的fetchTask函数,这时如果没有则会让工人等待,有则把第一个任务给他,然后周而复始进行这一过程.
运行结果示例
工人:王进喜取得任务:培训 工人:时传详取得任务:锻造 工人:张秉贵取得任务:打磨 工人:徐虎取得任务:车阶梯 正在处理的任务任务名:培训 工人名:王进喜 完成度:0% 完成度 完成度:0%个. 正在处理的任务任务名:锻造 工人名:时传详 完成度:0% 完成度 完成度:0%个. 正在处理的任务任务名:打磨 工人名:张秉贵 完成度:0% 完成度 完成度:0%个. 正在处理的任务任务名:车阶梯 工人名:徐虎 完成度:0% 完成度 完成度:0%个. 正在处理的任务任务名:培训 工人名:王进喜 完成度:12% 完成度 完成度:12%个. 正在处理的任务任务名:锻造 工人名:时传详 完成度:50% 完成度 完成度:50%个. 任务任务名:锻造 工人名:时传详 完成度:100%处理完毕! 工人:时传详取得任务:热处理 正在处理的任务任务名:打磨 工人名:张秉贵 完成度:60% 完成度 完成度:60%个. 任务任务名:打磨 工人名:张秉贵 完成度:100%处理完毕! 正在处理的任务任务名:车阶梯 工人名:徐虎 完成度:50% 完成度 完成度:50%个. 任务任务名:车阶梯 工人名:徐虎 完成度:100%处理完毕! 工人:徐虎取得任务:去皮 工人:张秉贵取得任务:镗孔 正在处理的任务任务名:培训 工人名:王进喜 完成度:25% 完成度 完成度:25%个. 正在处理的任务任务名:热处理 工人名:时传详 完成度:0% 完成度 完成度:0%个. 正在处理的任务任务名:去皮 工人名:徐虎 完成度:0% 完成度 完成度:0%个. 正在处理的任务任务名:镗孔 工人名:张秉贵 完成度:0% 完成度 完成度:0%个. 正在处理的任务任务名:培训 工人名:王进喜 完成度:37% 完成度 完成度:37%个. 正在处理的任务任务名:热处理 工人名:时传详 完成度:28% 完成度 完成度:28%个. 正在处理的任务任务名:去皮 工人名:徐虎 完成度:37% 完成度 完成度:37%个. 正在处理的任务任务名:镗孔 工人名:张秉贵 完成度:5% 完成度 完成度:5%个. 正在处理的任务任务名:培训 工人名:王进喜 完成度:50% 完成度 完成度:50%个. 正在处理的任务任务名:热处理 工人名:时传详 完成度:57% 完成度 完成度:57%个. 正在处理的任务任务名:去皮 工人名:徐虎 完成度:75% 完成度 完成度:75%个. 任务任务名:去皮 工人名:徐虎 完成度:100%处理完毕! 工人:徐虎取得任务:钻孔