一个简单的ThreadPool分析

来源:互联网 发布:mac防火墙屏蔽网址 编辑:程序博客网 时间:2024/05/17 02:55
导读:
   原文来自http://www.informit.com/articles/printerfriendly.asp?p=30483&r1=1&rl=1
   项目是多线程的,所以引入了线程池这个东西。池子是个老美写的。在项目中表现的还不错。所以把它摘出来,介绍给以后或许需要用到它的同行们。
   关于为什么要采用ThreadPool,原文已经提到了:创建一个线程是需要开销的;如果线程数量过大的话,cpu就会浪费很大的精力做线程切换。
   ThreadPool的实现过程就是对WorkerThread的同步和通信的管理过程。
   我们来看代码。
   首先,在ThreadPool构造的时候,创建10个WorkerThread(size=10)并让他们运行。每个WorkerThread线程都有个ThreadPool的引用,用于查询ThreadPool的状态和获得同步锁.WorkerThread运行以后,循环调用ThreadPool的方法进行查询,如果没有发现任务,ThreadPool告诉正在查询的线程进入休眠状态,WorkerThread释放对查询方法的锁定.这样在还没有任务的时候,所有的10个WorkerThread都会进入休眠状态,进入等待ThreadPool对象的等待锁定池,只有ThreadPool对象发出notify方法(或notifyAll)后WorkerThread线程才进入对象锁定池准备获得对象锁进入运行状态。
  代码片断:
  while ( !assignments.iterator().hasNext() )
   wait();
  如果你有jprofile或者其他的观察线程的工具,你可以看到有10个线程都在休眠状态.
   接着,我们向ThreadPool中加入任务,这些任务都实现了Runnable的run方法.(至于为什么把任务都做成Runnable,译者至今也有些疑问?预定俗成?TimerTask也是实现自Runnable,弄得初学者经常把真正运行的线程搞混).ThreadPool每assign一个任务,就会发出一条消息,通知它的等待锁定池中的线程.各个线程以抢占的方式获得对象锁,然后很顺利的获得一条任务.并把此任务从ThreadPool里面删除.没有抢到的继续等待.
  Runnable r = (Runnable)assignments.iterator().next();
  assignments.remove(r);
  WorkerThread从ThreadPool那里获得了任务,继续向下执行。
  target = owner.getAssignment();
  if (target!=null) {
   target.run();?????
   owner.done.workerEnd();
  }
  记住,这里调用的是target.run();而不是调用的线程的start()方法。也就是说在这里表现出的WorkerThread和task之间的关系仅仅是简单的方法调用的关系,并没有额外产生新线程。(这就是我上面纳闷为什么大家都实现Runnable来做task的原因)
  大家可能注意到,WorkerThread并没有对异常作处理。而我们知道发生在线程上的异常会导致线程死亡。解决的办法有2中,一种是通过threadpool的管理来重新激起一个线程,一种是把异常在线程之内消灭。在项目中,我采用的是第二中,因此这个片断改称这样:
  if (target!=null) {
   try{
   target.run();?????
  }
   catch(Throwable t){
  .......
  }
   owner.done.workerEnd();
  }
  在WorkerThread完成一个task以后,继续循环作同样的流程.
  在这个ThreadPool的实现里面,Jeff Heaton用了一个Done类来观察WorkerThread的执行情况.和ThreadPoool的等待锁定池不同,Done的等待锁定池里面放的是初始化ThreadPool的线程(可能是你的主线程),我们叫他母线程.
   在给出的测试例子中.母线程在调用complete()方法后进入休眠(在监视中等待),一开始是waitBegin()让他休眠,在assign加入task以后,waitDone()方法让他休眠.在WorkerThread完成一个task以后,通知waitDone()起来重新检查activeThreads的数值.若不为0,继续睡觉.若为0,那么母线程走完,死亡(这个时候该做的task已经做完了).母线程走完,ThreadPool还存在吗?答案是存在,因为WorkerThread还没有消亡,他们在等待下一批任务,他们有ThreadPool的引用,保证ThreadPool依然存在.大家或许已经明白Done这个类的作用了.
   细心的读者或许会发现,发生在Done实例上的notify()并不是像ThreadPool上的notify()那样每次都能完成一项工作.比如除了第一个被assign的task,其他的task在assign进去的时候,发出的notify()对于waitDone()来说是句"狼来了".
  最后在ThreadPool需要被清理得时候,使每一个WorkerThread中断(这个时候或许所有的WorkerThread都在休眠)并销毁.记住这里也是一个异步的过程.等到每一个WorkerThread都已经销毁,finalize()的方法体走完.ThreadPool被销毁.
  for (int i=0;i  threads[i].interrupt();
  done.workerBegin();
  threads[i].destroy();
   }
   done.waitDone();
  为什么有句done.workerBegin();?不明白.
  参考文章:

本文转自
http://www.blogjava.net/huabingl/archive/2006/07/16/58451.html
原创粉丝点击