這篇文章是"
調度員,工人及任務的OO分析過程"的續篇.
上次的情況是由調度員主動分配任務,但有些情況下需要工人自動取得任務而不是由調度員分配,這時需要對線程進行通知,使用的主要方法就是對象的wait(),notify(),notifyAll()三個函數,它們都必須從同步方法(synchronized method)中調用.
這種情況下事務的大致流程是:工人從任務庫中取得一項任務進行作業,完成后再取下一項,如果任務庫中沒有任務則進入等待狀態,如果任務庫有新任務則通知工人來取.
這次新引入了一個任務庫類TaskLibrary,它取代了上次的調度員類,代碼如下:
package com.sitinspring.autotask.domain;

import java.util.LinkedList;
import java.util.List;


/** *//**
* 任務庫類
*
* @author sitinspring(junglesong@gmail.com)
*
*/

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;
}
}
其中,fetchTask通過調用wait方法,實現了沒有任務時則對自己(this)加鎖(lock),以讓進入的線程等待,否則讓工人取走最開頭的任務.
而addTask和addTasks通過調用notifyAll方法,通知等待的線程可以繼續進行原來陷入等待狀態的流程.
在這種情況下,工人類只需關心當前任務即可,它無須保存一個任務列表,具體代碼如下:
package com.sitinspring.autotask.domain;

import com.sitinspring.autotask.util.IdUtil;


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();
}
}
}


public String getName()
{
return name;
}


public void setName(String name)
{
this.name = name;
}


public String getId()
{
return id;
}
}
它的Run方法實現了不斷取活干活的過程,因為具體進入等待是TaskLibrary做的,所以這個類代碼很簡單,這里就不贅述了.
執行過程如下:
package com.sitinspring.autotask;

import java.util.LinkedList;
import java.util.List;

import com.sitinspring.autotask.domain.Task;
import com.sitinspring.autotask.domain.TaskLibrary;
import com.sitinspring.autotask.domain.Worker;



public class Test
{

public static void main(String[] args)
{
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);
}

private static void sleep(int sleepSecond)
{

try
{
Thread.sleep(sleepSecond*1000);
}

catch(Exception ex)
{
ex.printStackTrace();
}
}
}
執行效果如下:
工人:王進喜取得任務:培訓
工人:時傳詳取得任務:鍛造
工人:張秉貴取得任務:打磨
工人:徐虎取得任務:車階梯
正在處理的任務任務名:培訓 工人名:王進喜 完成度: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%處理完畢!
工人:徐虎取得任務:鉆孔
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:10% 完成度 完成度:10%個.
正在處理的任務任務名:培訓 工人名:王進喜 完成度:62% 完成度 完成度:62%個.
正在處理的任務任務名:熱處理 工人名:時傳詳 完成度:85% 完成度 完成度:85%個.
任務任務名:熱處理 工人名:時傳詳 完成度:100%處理完畢!
工人:時傳詳取得任務:拉槽
正在處理的任務任務名:鉆孔 工人名:徐虎 完成度:0% 完成度 完成度:0%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:15% 完成度 完成度:15%個.
正在處理的任務任務名:培訓 工人名:王進喜 完成度:75% 完成度 完成度:75%個.
正在處理的任務任務名:拉槽 工人名:時傳詳 完成度:0% 完成度 完成度:0%個.
正在處理的任務任務名:鉆孔 工人名:徐虎 完成度:30% 完成度 完成度:30%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:20% 完成度 完成度:20%個.
正在處理的任務任務名:培訓 工人名:王進喜 完成度:87% 完成度 完成度:87%個.
任務任務名:培訓 工人名:王進喜 完成度:100%處理完畢!
工人:王進喜取得任務:鑄造
正在處理的任務任務名:拉槽 工人名:時傳詳 完成度:18% 完成度 完成度:18%個.
正在處理的任務任務名:鉆孔 工人名:徐虎 完成度:60% 完成度 完成度:60%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:25% 完成度 完成度:25%個.
正在處理的任務任務名:鑄造 工人名:王進喜 完成度:0% 完成度 完成度:0%個.
正在處理的任務任務名:拉槽 工人名:時傳詳 完成度:36% 完成度 完成度:36%個.
正在處理的任務任務名:鉆孔 工人名:徐虎 完成度:90% 完成度 完成度:90%個.
任務任務名:鉆孔 工人名:徐虎 完成度:100%處理完畢!
工人:徐虎取得任務:校驗
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:30% 完成度 完成度:30%個.
正在處理的任務任務名:鑄造 工人名:王進喜 完成度:12% 完成度 完成度:12%個.
正在處理的任務任務名:拉槽 工人名:時傳詳 完成度:54% 完成度 完成度:54%個.
正在處理的任務任務名:校驗 工人名:徐虎 完成度:0% 完成度 完成度:0%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:35% 完成度 完成度:35%個.
正在處理的任務任務名:鑄造 工人名:王進喜 完成度:25% 完成度 完成度:25%個.
正在處理的任務任務名:拉槽 工人名:時傳詳 完成度:72% 完成度 完成度:72%個.
正在處理的任務任務名:校驗 工人名:徐虎 完成度:33% 完成度 完成度:33%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:40% 完成度 完成度:40%個.
正在處理的任務任務名:鑄造 工人名:王進喜 完成度:37% 完成度 完成度:37%個.
正在處理的任務任務名:拉槽 工人名:時傳詳 完成度:90% 完成度 完成度:90%個.
任務任務名:拉槽 工人名:時傳詳 完成度:100%處理完畢!
工人:時傳詳取得任務:內務
正在處理的任務任務名:校驗 工人名:徐虎 完成度:66% 完成度 完成度:66%個.
任務任務名:校驗 工人名:徐虎 完成度:100%處理完畢!
任務告罄
工人:徐虎進入閑置狀態
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:45% 完成度 完成度:45%個.
正在處理的任務任務名:鑄造 工人名:王進喜 完成度:50% 完成度 完成度:50%個.
正在處理的任務任務名:內務 工人名:時傳詳 完成度:0% 完成度 完成度:0%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:50% 完成度 完成度:50%個.
正在處理的任務任務名:鑄造 工人名:王進喜 完成度:62% 完成度 完成度:62%個.
正在處理的任務任務名:內務 工人名:時傳詳 完成度:20% 完成度 完成度:20%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:55% 完成度 完成度:55%個.
正在處理的任務任務名:鑄造 工人名:王進喜 完成度:75% 完成度 完成度:75%個.
正在處理的任務任務名:內務 工人名:時傳詳 完成度:40% 完成度 完成度:40%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:60% 完成度 完成度:60%個.
正在處理的任務任務名:鑄造 工人名:王進喜 完成度:87% 完成度 完成度:87%個.
任務任務名:鑄造 工人名:王進喜 完成度:100%處理完畢!
任務告罄
工人:王進喜進入閑置狀態
正在處理的任務任務名:內務 工人名:時傳詳 完成度:60% 完成度 完成度:60%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:65% 完成度 完成度:65%個.
正在處理的任務任務名:內務 工人名:時傳詳 完成度:80% 完成度 完成度:80%個.
任務任務名:內務 工人名:時傳詳 完成度:100%處理完畢!
任務告罄
工人:時傳詳進入閑置狀態
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:70% 完成度 完成度:70%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:75% 完成度 完成度:75%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:80% 完成度 完成度:80%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:85% 完成度 完成度:85%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:90% 完成度 完成度:90%個.
正在處理的任務任務名:鏜孔 工人名:張秉貴 完成度:95% 完成度 完成度:95%個.
任務任務名:鏜孔 工人名:張秉貴 完成度:100%處理完畢!
任務告罄
工人:張秉貴進入閑置狀態

代碼下載:
http://www.tkk7.com/Files/sitinspring/AutoTask20071020100536.rar