ITPub博客

首页 > 应用开发 > IT综合 > 一个线程池实例(继续)

一个线程池实例(继续)

原创 IT综合 作者:westlifesz 时间:2007-01-18 15:48:23 0 删除 编辑
2006.12.12花了3个小时把 一个线程池实例 这篇文章讲的线程池例子读明白了!下面是这个程序的注释,以后再加上心得体会。[@more@]

import java.util.Vector;

public class ThreadPool {
public static final int MAX_THREADS = 100; //最大线程数
public static final int MAX_SPARE_THREADS = 50; //最大空闲线程数
public static final int MIN_SPARE_THREADS = 10; //最小空闲线程数
public static final int WORK_WAIT_TIMEOUT = 60 * 1000; //超时时间

protected Vector pool; //类全局变量,装线程的,里面加入ControlRunnable实例
protected MonitorRunnable monitor; //监控线程内部类全局变量
protected int maxThreads;
protected int minSpareThreads;
protected int maxSpareThreads;
protected int currentThreadCount;
protected int currentThreadsBusy;
protected boolean stopThePool;

public ThreadPool() {
maxThreads = MAX_THREADS;
maxSpareThreads = MAX_SPARE_THREADS;
minSpareThreads = MIN_SPARE_THREADS;
currentThreadCount = 0;
currentThreadsBusy = 0;
stopThePool = false;
}

public synchronized void start() {
adjustLimits();
openThreads(minSpareThreads);

//启动监控线程,程序开始运行
monitor = new MonitorRunnable(this);
}

public void setMaxThreads(int maxThreads) {
this.maxThreads = maxThreads;
}

public int getMaxThreads() {
return maxThreads;
}

public void setMinSpareThreads(int minSpareThreads) {
this.minSpareThreads = minSpareThreads;
}

public int getMinSpareThreads() {
return minSpareThreads;
}

public void setMaxSpareThreads(int maxSpareThreads) {
this.maxSpareThreads = maxSpareThreads;
}

public int getMaxSpareThreads() {
return maxSpareThreads;
}

/*
这个方法给外部调用,把具体的任务传进来。从这个方法可以看到,它实际上是把任务接过来,判断当前线程有多少,有空闲的就到池里面去取,实际上是调用池里面的ControlRunnable线程来干活!
为什么要通过它呢,因为它是ThreadPool类的方法,总协调人,来管理pool,线程数等东西。而ControlRunnable线程就是只管干活的,是在pool里面真正干活的线程。
*/
public void runIt(ThreadPoolRunnable r) {
if (null == r) {
throw new NullPointerException();
}
if (0 == currentThreadCount || stopThePool) {
throw new IllegalStateException();
}
ControlRunnable c = null;
synchronized (this)
{
//刚开始的时候currentThreadCount是 start() 里调用的 openThreads(minSpareThreads) 方法的minSpareThreads参数设置的,是10个。刚开始(第一个任务进来),currentThreadsBusy是为零,所以下面的if条件部成立,运行下去到currentThreadsBusy++;就表示有个线程在忙了!
if (currentThreadsBusy == currentThreadCount)
{
if (currentThreadCount < maxThreads) {
int toOpen = currentThreadCount + minSpareThreads;
openThreads(toOpen);
} else {
while (currentThreadsBusy == currentThreadCount) {
try {
this.wait();
}catch (InterruptedException e) {
}
if (0 == currentThreadCount || stopThePool) {
throw new IllegalStateException();
}
}
}
}

//找到pool里最末端的一个线程。然后从pool里除去,currentThreadsBusy加1,表示忙的线程多一个了。
c = (ControlRunnable) pool.lastElement();

/*
为什么要把我从池里面摘掉呢?难到以后还把我加进来?对了!在ControlRunnable里面运行完任务后,会调用 returnController 方法,returnController方法的参数就是removeElement掉的这个ControlRunnable,又加进到pool来了。
*/
pool.removeElement(c);
currentThreadsBusy++;
}
c.runIt(r); //上面从pool里取出来线程了ControlRunnable,调用它的runIt方法,开始运行!
}

public synchronized void shutdown() {
if (!stopThePool) {
stopThePool = true;
monitor.terminate();
monitor = null;
for (int i = 0; i < (currentThreadCount - currentThreadsBusy); i++) {
try {
((ControlRunnable) (pool.elementAt(i))).terminate();
} catch (Throwable t) {
}
}
currentThreadsBusy = currentThreadCount = 0;
pool = null;
notifyAll();
}
}

protected synchronized void checkSpareControllers() {
if (stopThePool) {
return;
}

//如果当前线程个数 - 正在繁忙的线程 比 最大空闲线程数大,释放多的线程
if ((currentThreadCount - currentThreadsBusy) > maxSpareThreads) {
int toFree = currentThreadCount - currentThreadsBusy - maxSpareThreads;
for (int i = 0; i < toFree; i++) {
//
ControlRunnable c = (ControlRunnable) pool.firstElement();
pool.removeElement(c);
c.terminate();
currentThreadCount--;
}
}
}

protected synchronized void returnController(ControlRunnable c) {
if (0 == currentThreadCount || stopThePool) {
c.terminate();
return;
}
currentThreadsBusy--;

pool.addElement(c); //把开始pool.removeElement(c);掉的ControlRunnable线程加进来。
notify(); //加进来就加进来了,还通知谁?难道有人在等你?
}

protected synchronized void notifyThreadEnd() {
currentThreadsBusy--;
currentThreadCount--;
notify();
openThreads(minSpareThreads);
}

protected void adjustLimits() {
if (maxThreads <= 0) {
maxThreads = MAX_THREADS;
}
if (maxSpareThreads >= maxThreads) {
maxSpareThreads = maxThreads;
}
if (maxSpareThreads <= 0) {
if (1 == maxThreads) {
maxSpareThreads = 1;
} else {
maxSpareThreads = maxThreads / 2;
}
}
if (minSpareThreads > maxSpareThreads) {
minSpareThreads = maxSpareThreads;
}
if (minSpareThreads <= 0) {
if (1 == maxSpareThreads) {
minSpareThreads = 1;
} else {
minSpareThreads = maxSpareThreads / 2;
}
}
}

/*
刚开始时由ThreadPool的start()调用,toOpen = minSpareThreads = 10. 刚开始运行的时候,线程池会往Vector对象里装入minSpareThreads个元素,每个元素都是ControlRunnable线程类,ControlRunnable类在其构造方法中启动线程。
*/
protected void openThreads(int toOpen) {
if (toOpen > maxThreads) {
toOpen = maxThreads;
}
if (0 == currentThreadCount) {
pool = new Vector(toOpen); //初始开minSpareThreads 10个元素
}

/*
每个元素是ControlRunnable(this)内部类,ControlRunnable的通过构造方法里面开始干活了!
*/
for (int i = currentThreadCount; i < toOpen; i++) {
pool.addElement(new ControlRunnable(this)); //new ControlRunnable,把它加进去
}
currentThreadCount = toOpen; //当前线程个数,就是上一步addElement加进去的。
}

/* 监控线程的内部类,为什么要用一个类呢?而不用个方法?因为是个类的话,它可以执行Runnable接口,为什么要继承Runnable接口呢?因为要在这里面开个线程,而这个线程干什么事呢?就是执行Runnable的run()方法-》监控当前线程个数:如果当前线程个数 - 正在繁忙的线程 比 最大空闲线程数大,释放多的线程.这个内部类是在
star()方法里通过 monitor = new MonitorRunnable(this); 开始运行. 这个内部类就是一直在监控线程数量,起到这么个作用。(当然还有个terminate()方法,来中止运行程序的。
*/
class MonitorRunnable implements Runnable {
ThreadPool p;
Thread t;
boolean shouldTerminate;

//构造方法把一个ThreadPool实例传过来
MonitorRunnable(ThreadPool p) {
shouldTerminate = false;
this.p = p; //保存ThreadPool实例给自己

t = new Thread(this); //new一个线程
t.start(); //开始运行一个线程,运行下面的run()方法:
}
public void run() {
while (true) {
try {
synchronized (this) {
this.wait(WORK_WAIT_TIMEOUT);
}
if (shouldTerminate) { //中止运行吗?
break;
}

/*
一直检测当前线程数,如果当前线程个数 - 正在繁忙的线程 比 最大空闲线程数大,释放多的线程,具体见ThreadPool的checkSpareControllers方法
*/
p.checkSpareControllers();
} catch (Throwable t) {
t.printStackTrace();
}
}
}

public synchronized void terminate() {
shouldTerminate = true; //中止运行程序
this.notify();
}
}

/*
又是一个执行Runnable接口的内部类,这个线程类是在Vector pool里面,具体运行扔给它的任务,和上面监控内部类一样,这个执行Runnable接口里面new thread线程,开始干活了!
*/
class ControlRunnable implements Runnable {
ThreadPool p;
Thread t;
ThreadPoolRunnable toRun; //具体要运行的任务
boolean shouldTerminate;
boolean shouldRun;
boolean noThData;
Object thData[] = null; //对象数组

/*
ControlRunnable类的构造方法,在构造方法里即开始new Thread,开始run()。
*/
ControlRunnable(ThreadPool p)
{
toRun = null;
shouldTerminate = false;
shouldRun = false;
this.p = p;
t = new Thread(this);
t.start();
noThData = true;
thData = null;
}


public void run() {
while (true) { //在一个循环里面开始工作
try {
synchronized (this) {
/*
刚开始shouldRun和shouldTerminate都是false,这个线程一直在这等wait(),
等待别人notify()。
*/
if (!shouldRun && !shouldTerminate) {
this.wait();
}
}
//如果调用了它自己的terminate()方法,里面会设置shouldTerminate为true,就break,不干了!
if (shouldTerminate) {
break;
}

/*
这个线程到这里就是开始干活了!肯定是某个调用了它自己的runIt()方法,因为这个方法里面有 shouldRun = true; 和 this.notify(); notify()把上面的wait();唤醒了,别睡了,干活吧!
而且runIt(ThreadPoolRunnabletoRun)里面会传过来一个ThreadPoolRunnable实例,就是真正要做的事情,有任务来了,开干!!
*/
try {
if (noThData) {
thData = toRun.getInitData();
noThData = false;
}
if (shouldRun)
{
//具体的任务类。我把线程给你开了,现在你有事情做,就做你自己的事吧。just do it!
toRun.runIt(thData);
}
} catch (Throwable t) {
System.err.println("ControlRunnable Throwable: ");
t.printStackTrace();
shouldTerminate = true;
shouldRun = false;
p.notifyThreadEnd();
}

//跑到finally这来了,肯定事干完了,把shouldRun设为false,然后调用returnController,把这个线程又加到pool里去!
finally {
if (shouldRun) {
shouldRun = false;
p.returnController(this);
}
}
if (shouldTerminate) {
break;
}
} catch (InterruptedException ie) {
}
}
}

public synchronized void runIt(ThreadPoolRunnable toRun) {
if (toRun == null) {
throw new NullPointerException("No Runnable");
}
this.toRun = toRun;
shouldRun = true;
this.notify();
}

//中止运行这个线程,并告诉 this.notify() 别人( this.wait() )不等了;
public synchronized void terminate() {
shouldTerminate = true;
this.notify();
}
}
}

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/7577965/viewspace-891258/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
  • 博文量
    16
  • 访问量
    11096