tomcat源码学习--线程池

写个前言:
通常大家知道tomcat的线程池是可以配置的,去找到conf下面的的server.xml就可以搞定,先配置指定参数
[quote]
<Service name="Catalina">

<!--The connectors can use a shared executor, you can define one or more named thread pools-->
<!--
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
-->
[/quote]
在配置连接器使用它,注释中都给出了例子
[quote]
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<!-- A "Connector" using the shared thread pool-->
<!--
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
-->
[/quote]

但现在不是想说这个,是想看看tomcat源码里的线程池,只看配置文件没啥意义,不好玩
[size=large]开始->>[/size]
[size=medium] 首先看tomcat的源码,ThreadPool里面的成员变量[/size]

private static Log log = LogFactory.getLog(ThreadPool.class);

private static StringManager sm =
StringManager.getManager("org.apache.tomcat.util.threads.res");

private static boolean logfull=true;

/*
* Default values ...
*/
public static final int MAX_THREADS = 200;
public static final int MAX_THREADS_MIN = 10;
public static final int MAX_SPARE_THREADS = 50;
public static final int MIN_SPARE_THREADS = 4;
public static final int WORK_WAIT_TIMEOUT = 60*1000;

/*
* Where the threads are held.
*/
protected ControlRunnable[] pool = null;

/*
* A monitor thread that monitors the pool for idel threads.
*/
protected MonitorRunnable monitor;


/*
* Max number of threads that you can open in the pool.
*/
protected int maxThreads;

/*
* Min number of idel threads that you can leave in the pool.
*/
protected int minSpareThreads;

/*
* Max number of idel threads that you can leave in the pool.
*/
protected int maxSpareThreads;

/*
* Number of threads in the pool.
*/
protected int currentThreadCount;

/*
* Number of busy threads in the pool.
*/
protected int currentThreadsBusy;

/*
* Flag that the pool should terminate all the threads and stop.
*/
protected boolean stopThePool;

/* Flag to control if the main thread is 'daemon' */
protected boolean isDaemon=true;

/** The threads that are part of the pool.
* Key is Thread, value is the ControlRunnable
*/
protected Hashtable threads=new Hashtable();

protected Vector listeners=new Vector();

/** Name of the threadpool
*/
protected String name = "TP";

/**
* Sequence.
*/
protected int sequence = 1;

/**
* Thread priority.
*/
protected int threadPriority = Thread.NORM_PRIORITY;


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

[size=medium] 构造函数里面默认指定了线程池配置的东西,这里的每个参数就不说了,tomcat用在这个类里面即对线程池用到的参数使用变量+常量 形式让这个可配置型增加,也好理解修改

构造线程池的策略是什么呢?一个Hashtable来键值对存储[/size]
[quote]
/** The threads that are part of the pool.
* Key is Thread, value is the ControlRunnable
*/
protected Hashtable threads=new Hashtable();


public void addThread( Thread t, ControlRunnable cr ) {
threads.put( t, cr );
for( int i=0; i<listeners.size(); i++ ) {
ThreadPoolListener tpl=(ThreadPoolListener)listeners.elementAt(i);
tpl.threadStart(this, t);
}
}

public void removeThread( Thread t ) {
threads.remove(t);
for( int i=0; i<listeners.size(); i++ ) {
ThreadPoolListener tpl=(ThreadPoolListener)listeners.elementAt(i);
tpl.threadEnd(this, t);
}
}
[/quote]
[size=medium] 里面的key经过了多层的包装,他里面封装了很多信息ThreadWithAttributes,这一切都是通过里面的内部类ControlRunnable来实现的,内部类真是个好东西,好多复杂的东西都写在里面,是不是业务逻辑复杂,抽取成方法也不好时,可以考虑抽取内部类[/size]

[size=medium] 线程池启动时,做一些init工作,主要是把 pool monitor给初始化, adjustLimits()是一个防止你配置错误的validate,如果错误他会有些策略,有兴趣可以看下。完成这一切后。怎么处理线程呢?在newC的时候就[/size]

public synchronized void start() {
stopThePool=false;
currentThreadCount = 0;
currentThreadsBusy = 0;

adjustLimits();

pool = new ControlRunnable[maxThreads];
/**这个内部类的构造函数
ControlRunnable(ThreadPool p) {
toRun = null;
shouldTerminate = false;
shouldRun = false;
this.p = p;
t = new ThreadWithAttributes(p, this);
t.setDaemon(true);
t.setName(p.getName() + "-Processor" + p.incSequence());
t.setPriority(p.getThreadPriority());
p.addThread( t, this );
noThData=true;
/**这个start听复杂的,看这运行key的,但可以是ThreadWithAttributes,他继承自Thread,那么它部是空吗?不是在构造方法里面 super(r);这个方法以为着运行目标变成当前类ControlRunnable*/
t.start();
}
创建的数组也并没初始化这个构造函数,有这样一个方法,刚开始直接给你构造好最小个线程
protected void openThreads(int toOpen) {

if(toOpen > maxThreads) {
toOpen = maxThreads;
}

for(int i = currentThreadCount ; i < toOpen ; i++) {
/**居然还是倒着往里面赋值**/
pool[i - currentThreadsBusy] = new ControlRunnable(this);
}

currentThreadCount = toOpen;
}

**/

openThreads(minSpareThreads);
if (maxSpareThreads < maxThreads) {
monitor = new MonitorRunnable(this);
}
}


[size=medium] 初始化一切搞定,当线程调用run,那么会去查找相关已经初始化的线程,再取出来,对应去运行[/size]

public void run(Runnable r) {
ControlRunnable c = findControlRunnable();
c.runIt(r);
}



[size=medium]那么着就完了吗?tomcat还提供了一个接口,你要使用线程池只需继承它是想相关的东西[/size]

/** Implemented if you want to run a piece of code inside a thread pool.
*/
public interface ThreadPoolRunnable {
// XXX use notes or a hashtable-like
// Important: ThreadData in JDK1.2 is implemented as a Hashtable( Thread -> object ),
// expensive.

/** Called when this object is first loaded in the thread pool.
* Important: all workers in a pool must be of the same type,
* otherwise the mechanism becomes more complex.
*/
public Object[] getInitData();

/** This method will be executed in one of the pool's threads. The
* thread will be returned to the pool.
*/
public void runIt(Object thData[]);

}

[size=medium] 那么tomcat又在何处使用它了,利用eclipse工具,找到调用类PoolTcpEndpoint,里面的线程是LeaderFollowerWorkerThread还实现了ThreadPoolRunnable,感兴趣可以自己去看看

综上所述,它实现是怎样的,先初始化一定数量的线程,他们都先睡着,线程池 runIt(listener)传入线程,传入后就不notify然后就 shouldRun = true,然后就调用传进来的线程。但是包装的东西好多啊,控制的东西验证的东西也好多,造成了这个类好大。[/size]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值