本文內(nèi)容
本文將從一個現(xiàn)實例子來實際說明線程調(diào)度方法wait,notify和notifyAll的使用。
工廠中任務(wù)的領(lǐng)受和執(zhí)行
某工廠執(zhí)行這樣的機(jī)制:當(dāng)生產(chǎn)任務(wù)下達(dá)到車間時會統(tǒng)一放在一個地方,由工人們來取活。
工人取活如此執(zhí)行:一個工人手頭只能有一個活,如果沒做完不能做下一個,如果做完了則可以到公共的地方去取一個;如果沒有活可取則閑著直到來活為止。
本文就是講述怎樣使用線程的調(diào)度三方法wait,notify和notifyAll來實現(xiàn)這一現(xiàn)實活動的。
任務(wù)類Task-它用來實現(xiàn)一個”活”,其中關(guān)鍵的成員是完成需消耗的工時數(shù)manHour和已經(jīng)完成的工時數(shù)completed
public class Task implements Comparable {
private String id;
private String name;
// 完成需消耗的工時數(shù)
private int manHour;
// 已經(jīng)完成的工時數(shù)
private int completed;
// 優(yōu)先級
private int priority;
// 接受任務(wù)者
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;
}
// 任務(wù)是否完成
public boolean isCompleted() {
return completed >= manHour;
}
// 添加完成度
public void addCompleted(int n) {
completed += n;
if (isCompleted()) {
completed = manHour;
if (worker != null) {
System.out.println("任務(wù)"+this+"處理完畢!");
}
}
}
public int compareTo(Object obj) {
Task another = (Task) obj;
return (another.priority) - this.priority;
}
public String toString() {
return "任務(wù)名:" + name + " 工人名:" + worker.getName() + " 完成度:" + completed
* 100 / manHour + "%";
}
public String getCompletedRatio() {
return " 完成度:" + completed * 100 / manHour + "%";
}
...getter/setter方法省略..
}
任務(wù)庫類TaskLibrary
這個類對應(yīng)現(xiàn)實中的取活的地方,每個活Task放在這個類的成員tasks中,有兩個方法來添加單個任務(wù)和多個任務(wù),還有一個fetchTask方法來供工人領(lǐng)受任務(wù).
public class TaskLibrary {
private List<Task> tasks;
public TaskLibrary() {
tasks = new LinkedList<Task>();
}
// 添加單個任務(wù)
public synchronized void addTask(Task task) {
tasks.add(task);
notifyAll();
}
// 添加多個任務(wù)
public synchronized void addTasks(List<Task> moreTasks) {
tasks.addAll(moreTasks);
notifyAll();
}
public int getTaskSize() {
return tasks.size();
}
// 工人領(lǐng)受任務(wù)
public synchronized Task fetchTask(Worker worker) {
while (tasks.size() == 0) {
try {
System.out.println("任務(wù)告罄");
System.out.println("工人:" + worker.getName() + "進(jìn)入閑置狀態(tài)");
wait();
} catch (InterruptedException ex1) {
ex1.printStackTrace();
}
}
Task task = tasks.get(0);
System.out.println("工人:" + worker.getName() + "取得任務(wù):" + 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("正在處理的任務(wù)" + currTask + " 完成度"
+ currTask.getCompletedRatio() + "個.");
currTask.addCompleted(speed);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
。。。
}
運(yùn)行代碼
TaskLibrary taskLibrary=new TaskLibrary();
taskLibrary.addTask(new Task("培訓(xùn)",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("王進(jìn)喜",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("內(nèi)務(wù)",10));
sleep(3);
運(yùn)行情況分析
一開始先初始化任務(wù)庫,然后進(jìn)行給任務(wù)庫中添加任務(wù),初始化工人實例時會把任務(wù)庫實例的地址傳入,工人實例初始化完畢后會調(diào)用doWork函數(shù)去任務(wù)庫取任務(wù)開始做,這會進(jìn)入TaskLibrary類的fetchTask函數(shù),這時如果沒有則會讓工人等待,有則把第一個任務(wù)給他,然后周而復(fù)始進(jìn)行這一過程.
運(yùn)行結(jié)果示例
工人:王進(jìn)喜取得任務(wù):培訓(xùn) 工人:時傳詳取得任務(wù):鍛造 工人:張秉貴取得任務(wù):打磨 工人:徐虎取得任務(wù):車階梯 正在處理的任務(wù)任務(wù)名:培訓(xùn) 工人名:王進(jìn)喜 完成度:0% 完成度 完成度:0%個. 正在處理的任務(wù)任務(wù)名:鍛造 工人名:時傳詳 完成度:0% 完成度 完成度:0%個. 正在處理的任務(wù)任務(wù)名:打磨 工人名:張秉貴 完成度:0% 完成度 完成度:0%個. 正在處理的任務(wù)任務(wù)名:車階梯 工人名:徐虎 完成度:0% 完成度 完成度:0%個. 正在處理的任務(wù)任務(wù)名:培訓(xùn) 工人名:王進(jìn)喜 完成度:12% 完成度 完成度:12%個. 正在處理的任務(wù)任務(wù)名:鍛造 工人名:時傳詳 完成度:50% 完成度 完成度:50%個. 任務(wù)任務(wù)名:鍛造 工人名:時傳詳 完成度:100%處理完畢! 工人:時傳詳取得任務(wù):熱處理 正在處理的任務(wù)任務(wù)名:打磨 工人名:張秉貴 完成度:60% 完成度 完成度:60%個. 任務(wù)任務(wù)名:打磨 工人名:張秉貴 完成度:100%處理完畢! 正在處理的任務(wù)任務(wù)名:車階梯 工人名:徐虎 完成度:50% 完成度 完成度:50%個. 任務(wù)任務(wù)名:車階梯 工人名:徐虎 完成度:100%處理完畢! 工人:徐虎取得任務(wù):去皮 工人:張秉貴取得任務(wù):鏜孔 正在處理的任務(wù)任務(wù)名:培訓(xùn) 工人名:王進(jìn)喜 完成度:25% 完成度 完成度:25%個. 正在處理的任務(wù)任務(wù)名:熱處理 工人名:時傳詳 完成度:0% 完成度 完成度:0%個. 正在處理的任務(wù)任務(wù)名:去皮 工人名:徐虎 完成度:0% 完成度 完成度:0%個. 正在處理的任務(wù)任務(wù)名:鏜孔 工人名:張秉貴 完成度:0% 完成度 完成度:0%個. 正在處理的任務(wù)任務(wù)名:培訓(xùn) 工人名:王進(jìn)喜 完成度:37% 完成度 完成度:37%個. 正在處理的任務(wù)任務(wù)名:熱處理 工人名:時傳詳 完成度:28% 完成度 完成度:28%個. 正在處理的任務(wù)任務(wù)名:去皮 工人名:徐虎 完成度:37% 完成度 完成度:37%個. 正在處理的任務(wù)任務(wù)名:鏜孔 工人名:張秉貴 完成度:5% 完成度 完成度:5%個. 正在處理的任務(wù)任務(wù)名:培訓(xùn) 工人名:王進(jìn)喜 完成度:50% 完成度 完成度:50%個. 正在處理的任務(wù)任務(wù)名:熱處理 工人名:時傳詳 完成度:57% 完成度 完成度:57%個. 正在處理的任務(wù)任務(wù)名:去皮 工人名:徐虎 完成度:75% 完成度 完成度:75%個. 任務(wù)任務(wù)名:去皮 工人名:徐虎 完成度:100%處理完畢! 工人:徐虎取得任務(wù):鉆孔