这篇文章是"
调度员,工人及任务的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.blogjava.net/Files/sitinspring/AutoTask20071020100536.rar