http://www.cnjbb.org/thread.jsp?boardid=24&threadid=44955
设计目标
Ø 提供一个线程池的组件,具有良好的伸缩性,当线程够用时,销毁不用线程,当线程不够用时,自动增加线程数量;
Ø 提供一个工作任务接口和工作队列,工作队列只接受实现工作任务接口的的工作,工作任务可以自由在工作队列中取放,取出执行的工作任务将从工作队列中删除。
Ø 线程池中的线程从工作队列中,自动取得工作任务,执行任务。
主要控制类和功能接口设计
线程池管理器ThreadPoolManager的功能:
Ø 管理线程池中的各个属性变量
ü 初始化最大工作线程数
ü 初始化最小工作线程数
ü 存放线程的数据结构
ü 线程池线程增长步长
ü 任务工作队列
ü 线程活动标识位
ü 工作线程 监视狗
ü 空闲秒数
Ø 提供线程池启动接口
Ø 提供线程池销毁接口
工作线程WorkThread 的功能:
ü 从工作队列中获取工作任务
ü 执行工作任务
工作队列IWorkQueue 的功能:
Ø 提供加入任务接口;
Ø 提供删除任务接口;
Ø 提供取得任务总数接口;
Ø 提供删除所有任务接口;
工作任务接口 Itask 的功能:
Ø 提供执行任务接口.
核心代码:
CODE:
package com.teksen.component.multithread; import com.teksen.component.multithread.impl.MyTask; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import com.teksen.foundation.log.Logger; import com.teksen.foundation.log.LoggerFactory; /** * <p>Title: 线程池管理器</p> * <p>Description: </p> * <p>Copyright: Copyright (c) 2005</p> * <p>Company: </p> * @author not attributable * @version 1.0 */ public class ThreadPoolManager { /* 空闲60秒 */ public static final long DEFAULT_IDLE_TIMEOUT = 10000L; /* 空闲60秒 */ private long IDLE_TIMEOUT = DEFAULT_IDLE_TIMEOUT; /* 线程池线程增长步长 */ public static final int INCREASE_STEP = 2; /* 日志对象 */ private static final Logger log = LoggerFactory.getLogger(ThreadPoolManager.class); /* 线程活动标识位 */ private boolean active = true; /*最大线程数*/ private int threads_max_num; /*最小线程数*/ private int threads_min_num; /* 存放线程的数据结构 */ private List pool = new ArrayList(); /* 任务工作队列 */ private IWorkQueue queue; /* 工作线程 监视狗 */ private WorkThreadWatchDog dog ; /** * 线程池管理器 * @param queue 任务队列 * @param threads_min_num 工作线程最小数 * @param threads_max_num 工作线程最大数 */ public ThreadPoolManager(int threads_min_num ,int threads_max_num ,IWorkQueue queue){ this.threads_max_num = threads_max_num; this.threads_min_num = threads_min_num; this.queue = queue; log.debug(" ThreadPoolManager initalize data :"); log.debug(" =threads_max_num :"+threads_max_num); log.debug(" =threads_min_num :"+threads_min_num); log.debug(" =queue's :"+queue.getTaskSize()); } public ThreadPoolManager(int threads_min_num ,int threads_max_num ,IWorkQueue queue,long IDLE_TIMEOUT){ this(threads_min_num,threads_max_num,queue); if(IDLE_TIMEOUT>1000){ this.IDLE_TIMEOUT = IDLE_TIMEOUT; } } /** * 启动 */ public void startPool(){ dog = new WorkThreadWatchDog(); dog.setDaemon(true); dog.start(); log.debug(" ThreadPoolManager is startPool ."); } /** * 停止 */ public void stopPool(){ log.debug(" ThreadPoolManager is stopPool."); this.active = false; if(!dog.isInterrupted()){ try{ log.debug(dog.getName() + " ===>interrupt"); dog.interrupt(); synchronized(dog){ log.debug(dog.getName() + " ===>notifyAll"); dog.notifyAll(); } } catch(Throwable ex){ log.error(dog.getName() + " interrupt that is failure .",ex); } try{ log.debug(dog.getName() + " ===>join"); dog.join(); } catch(Throwable ex){ log.error(dog.getName() + " join:"+ex); } }// end if /* 删除所有活动线程 */ Iterator iterator = null; WorkThread tempThread = null; log.debug("destroy active threads ... starting..."); iterator = pool.iterator(); while(iterator.hasNext()){ tempThread = (WorkThread)iterator.next(); if(tempThread != null ){ if(tempThread.isAlive() && (!tempThread.isMyinterrupted() || !tempThread.isInterrupted() ) ){ synchronized(tempThread){ tempThread.notifyAll(); log.debug(tempThread.getName() + " ===>notifyAll"); }//end syn try{ log.debug(tempThread.getName() + " ===>interrupt"); tempThread.interrupt(); }catch(Throwable ex){ log.error(tempThread.getName() + " interrupt that is failure .",ex); } try{ log.debug(tempThread.getName() + " ===>join"); tempThread.join(); }catch(Throwable ex){ log.error(tempThread.getName() + " join that is failure .",ex); } } }//end if }//end while log.debug("destroy all active threads ... is ok ..."); pool.clear(); pool = null; dog = null; tempThread = null; log.debug("clear pool... is ok ..."); log.debug("stopPool ... end ok ... "); } /* * 工作线程狗,监视工作线程 */ class WorkThreadWatchDog extends Thread{ public WorkThreadWatchDog(){ super("WorkThread_WatchDog"); } public void run(){ WorkThread temp = null; //phase 1 ================================================================== log.debug(" WorkThreadWatchDog is run . "); /* 开启最小线程数 */ for(int i=0; i < threads_min_num ;i++){ temp = new WorkThread("ThreadPool_"+(i+1)); temp.start(); pool.add(temp); log.debug(temp.getName() + " is start [NEW]. "); }// end for temp = null; //phase 2 ================================================================== /* 线程总数,初始化为最小值 */ int poolsize = threads_min_num; /* 任务数 */ int tasksize = 0; /* 线程池走查器 */ Iterator poolIterator = null; /* 循环执行操作 */ for(long times=1; active && !this.isInterrupted(); times++){ /* 让狗睡眠指定时间 ========================*/ synchronized(this){ try{ log.debug(this.getName()+" wait a moment ... "); this.wait(IDLE_TIMEOUT); } catch(Throwable ex){ log.error(this.getName()+" wait:"+ex); break; } } /* 任务总数 */ tasksize = queue.getTaskSize(); log.debug("===========================Dog watch operate [New]:"+times); log.debug(this.getName()+": tasksize = "+tasksize); log.debug(this.getName()+": poolsize = "+poolsize); /* tasksize < (poolsize*2), 让狗按指定时间睡眠,并且收缩池 */ if(tasksize <= (poolsize*2) && poolsize > threads_min_num ){ /* 没有任务时,按步长缩减线程 ------------------------------------ */ log.debug(this.getName()+ " : tasksize <= (poolsize*2) and shrink thread pool ... "); /* 按步长程数 */ poolIterator = pool.iterator(); /* 线程关闭动作 */ for(int i=0; (i<INCREASE_STEP) && (poolsize > threads_min_num) && poolIterator.hasNext();i++){ /* workThread 实例的不同线程 */ temp = (WorkThread)poolIterator.next(); if(temp != null){ /* 关闭工作线程的睡眠标识为TRUE的线程 */ if((temp.isSleeped || !temp.isMyinterrupted()) && !temp.isInterrupted()){ --poolsize; temp.interrupt(); synchronized(temp){ temp.notifyAll(); } log.debug(temp.getName()+ " is shrinked."); } }// end if }//end for========================================== temp = null; }//收缩动作结束 /* * 有任务----------1 */ /* 当任务总数大于线程总数的两倍时,按步长增加线程 */ if(tasksize > (poolsize*2) && poolsize<threads_max_num){ log.debug(this.getName()+" is increase threads... "); /* 按步长程数 */ for(int i=0; i<INCREASE_STEP && poolsize<=threads_max_num ;i++){ ++poolsize; temp = new WorkThread("ThreadPool_"+poolsize); temp.start(); pool.add(temp); log.debug(temp.getName() + " is start [NEW]. "); }// end for temp = null; }//end if 结束伸动作. /* 唤醒所有钝化线程执行任务 ================*/ log.debug(this.getName()+ " wake up all passivated threads ... "); poolIterator = pool.iterator(); while(poolIterator != null &&poolIterator.hasNext()){ temp = (WorkThread)poolIterator.next(); if(temp != null ){ synchronized(temp){ temp.notifyAll(); } log.debug(this.getName()+ " Wake up the thread ["+temp.getName()+"]"); } }//end while temp = null; }//end while log.debug(this.getName() + " is over ... "); }//end run } /** * 工作线程 */ class WorkThread extends Thread{ private boolean isSleeped = false; private boolean isMyinterrupted = false; public boolean isMyinterrupted(){ return isMyinterrupted; } public WorkThread(String name){ super(name); } public void run(){ ITask task = null; String threadName="["+this.getName()+"]"; log.debug("this.currentThread:"+Thread.currentThread().getName()); /* 活动标志位 */ while(active && !isMyinterrupted && !isInterrupted()){ /* 获取任务 ,如果没有任务则等待 */ while((task = queue.getTask())==null){ synchronized(this){ try { log.debug(threadName + " wait ... "); this.isSleeped = true; wait(); this.isSleeped = false; log.debug(threadName + " is waked up ... "); } catch (Throwable ex) { log.error(threadName + " wait that is failure. ",ex); isMyinterrupted = true; this.isSleeped = false; break; } } }//end while---------- if(this.isInterrupted() || isMyinterrupted ){ log.debug(threadName + " is interrupted, break while cycle.[1]"); break; } /* 执行任务 */ try{ if(task != null){ log.debug(threadName + " excute owner task ... "); task.executeTask(); } }catch(Throwable ex){ log.error(threadName + " executeTask:"+ex); } }//end while log.debug(threadName + " the thread is already stoped ... "); } } public static void main(String[] args){ IWorkQueue queue = new WorkQueue(); ThreadPoolManager tm = new ThreadPoolManager(3,6,queue); tm.startPool(); for(int i=0; i<20 ; i++){ queue.addTask(new MyTask(i)); } try{ Thread.sleep(15000); tm.stopPool(); } catch(Throwable ex){ log.error("sleep:"+ex); } } }处理结果:
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPoolManager initalize data :
DEBUG com.teksen.component.multithread.ThreadPoolManager - =threads_max_num :6
DEBUG com.teksen.component.multithread.ThreadPoolManager - =threads_min_num :3
DEBUG com.teksen.component.multithread.ThreadPoolManager - =queue's :0
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPoolManager is startPool .
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThreadWatchDog is run .
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_1 is start [NEW].
DEBUG com.teksen.component.multithread.ThreadPoolManager - this.currentThread:ThreadPool_1
DEBUG com.teksen.component.multithread.WorkQueue - No task in queue !
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_1] wait ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_2 is start [NEW].
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_3 is start [NEW].
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog wait a moment ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - this.currentThread:ThreadPool_2
DEBUG com.teksen.component.multithread.WorkQueue - No task in queue !
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_2] wait ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - this.currentThread:ThreadPool_3
DEBUG com.teksen.component.multithread.WorkQueue - No task in queue !
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_3] wait ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - ===========================Dog watch operate [New]:1
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog: tasksize = 20
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog: poolsize = 3
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog is increase threads...
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_4 is start [NEW].
DEBUG com.teksen.component.multithread.ThreadPoolManager - this.currentThread:ThreadPool_4
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_5 is start [NEW].
DEBUG com.teksen.component.multithread.ThreadPoolManager - this.currentThread:ThreadPool_5
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_4] excute owner task ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog wake up all passivated threads ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_5] excute owner task ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog Wake up the thread [ThreadPool_1]
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_1] is waked up ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_1] excute owner task ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_2] is waked up ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_2] excute owner task ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog Wake up the thread [ThreadPool_2]
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_3] is waked up ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_3] excute owner task ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog Wake up the thread [ThreadPool_3]
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog Wake up the thread [ThreadPool_4]
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog Wake up the thread [ThreadPool_5]
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog wait a moment ...
MyTask[0] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_4] excute owner task ...
MyTask[1] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_5] excute owner task ...
MyTask[2] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_1] excute owner task ...
MyTask[3] executeTask.
MyTask[4] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_2] excute owner task ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_3] excute owner task ...
MyTask[6] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_5] excute owner task ...
MyTask[5] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_4] excute owner task ...
MyTask[7] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_1] excute owner task ...
MyTask[8] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_2] excute owner task ...
MyTask[9] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_3] excute owner task ...
MyTask[10] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_5] excute owner task ...
MyTask[11] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_4] excute owner task ...
MyTask[12] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_1] excute owner task ...
MyTask[13] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_2] excute owner task ...
MyTask[14] executeTask.
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_3] excute owner task ...
MyTask[15] executeTask.
DEBUG com.teksen.component.multithread.WorkQueue - No task in queue !
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_5] wait ...
MyTask[16] executeTask.
DEBUG com.teksen.component.multithread.WorkQueue - No task in queue !
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_4] wait ...
MyTask[17] executeTask.
DEBUG com.teksen.component.multithread.WorkQueue - No task in queue !
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_1] wait ...
MyTask[19] executeTask.
DEBUG com.teksen.component.multithread.WorkQueue - No task in queue !
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_3] wait ...
MyTask[18] executeTask.
DEBUG com.teksen.component.multithread.WorkQueue - No task in queue !
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_2] wait ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPoolManager is stopPool.
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog ===>interrupt
ERROR com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDogwait:java.lang.InterruptedException
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog is over ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog ===>notifyAll
DEBUG com.teksen.component.multithread.ThreadPoolManager - WorkThread_WatchDog ===>join
DEBUG com.teksen.component.multithread.ThreadPoolManager - destroy active threads ... starting...
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_1 ===>notifyAll
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_1 ===>interrupt
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_1 ===>join
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_1] is waked up ...
DEBUG com.teksen.component.multithread.WorkQueue - No task in queue !
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_1] wait ...
ERROR com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_1] wait that is failure.
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:429)
at com.teksen.component.multithread.ThreadPoolManager$WorkThread.run(ThreadPoolManager.java:330)
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_1] is interrupted, break while cycle.[1]
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_1] the thread is already stoped ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_2 ===>notifyAll
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_2 ===>interrupt
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_2] is waked up ...
DEBUG com.teksen.component.multithread.WorkQueue - No task in queue !
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_2] wait ...
ERROR com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_2] wait that is failure.
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:429)
at com.teksen.component.multithread.ThreadPoolManager$WorkThread.run(ThreadPoolManager.java:330)
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_2] is interrupted, break while cycle.[1]
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_2] the thread is already stoped ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_2 ===>join
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_3 ===>notifyAll
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_3 ===>interrupt
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_3 ===>join
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_3] is waked up ...
DEBUG com.teksen.component.multithread.WorkQueue - No task in queue !
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_3] wait ...
ERROR com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_3] wait that is failure.
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:429)
at com.teksen.component.multithread.ThreadPoolManager$WorkThread.run(ThreadPoolManager.java:330)
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_3] is interrupted, break while cycle.[1]
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_3] the thread is already stoped ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_4 ===>notifyAll
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_4 ===>interrupt
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_4 ===>join
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_4] is waked up ...
DEBUG com.teksen.component.multithread.WorkQueue - No task in queue !
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_4] wait ...
ERROR com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_4] wait that is failure.
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:429)
at com.teksen.component.multithread.ThreadPoolManager$WorkThread.run(ThreadPoolManager.java:330)
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_4] is interrupted, break while cycle.[1]
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_4] the thread is already stoped ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_5 ===>notifyAll
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_5 ===>interrupt
DEBUG com.teksen.component.multithread.ThreadPoolManager - ThreadPool_5 ===>join
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_5] is waked up ...
DEBUG com.teksen.component.multithread.WorkQueue - No task in queue !
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_5] wait ...
ERROR com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_5] wait that is failure.
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:429)
at com.teksen.component.multithread.ThreadPoolManager$WorkThread.run(ThreadPoolManager.java:330)
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_5] is interrupted, break while cycle.[1]
DEBUG com.teksen.component.multithread.ThreadPoolManager - [ThreadPool_5] the thread is already stoped ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - destroy all active threads ... is ok ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - clear pool... is ok ...
DEBUG com.teksen.component.multithread.ThreadPoolManager - stopPool ... end ok ...