和风细雨

世上本无难事,心以为难,斯乃真难。苟不存一难之见于心,则运用之术自出。

线程调度实例

本文内容

本文将从一个现实例子来实际说明线程调度方法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%处理完毕! 工人:徐虎取得任务:钻孔

 

posted on 2008-02-22 14:17 和风细雨 阅读(299) 评论(0)  编辑  收藏 所属分类: 线程


只有注册用户登录后才能发表评论。


网站导航: