Tomat组件研究之ThreadPool

Tomat组件研究之ThreadPool

   前几天曾向大家承诺,要完成ThredPoolTomcat SSl的文章,今天终于有时间可以写一点。TomcatThradPool不同于ApacheCommon ThradPoolTomcatThreadPool是专门为Tomcat服务的,确切说是为Tomcat处理Http连接服务地。经过研究发现,Apache用了及其难懂而又隐晦的方法写了这几个ThreadPool类,虽然仅简单的几个类,但其难理解的程度却是惊人的。在理解之后看,里面确实又值得我们学习的东西,但也有好多无用的东西。看来我们也不要盲目崇拜Apache。废话少说,下面直入正题.

ThreadPoolClass图及整体结构:

一.每个类的说明:

1.   org.apache.tomcat.util.threads.ThreadPool

   线程池类,本类仅维护一定数量的线程处理对象,而把具体执行操作的任务委派给其他对象(ControlRunnable),Apache并没有把过多的功能交给这个类,而仅只是让这个类维护线程的创建,销毁,取出,归还等功能。下面我们看该类的代码:

public class ThreadPool  {

(1)      线程池常量,对应的变量设置就不再列出了

    //最大线程数

    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;

//最大等待时间(1分钟)

    public static final int WORK_WAIT_TIMEOUT = 60*1000;

(2)      start方法

 

 

//对每个线程实例本方法仅被调用一次

    public synchronized void start() {

        //是否停止线程

        stopThePool=false;

        //当前生成线程的数量

        currentThreadCount  = 0;

        //当前使用线程的数量

        currentThreadsBusy  = 0;

        //如果当前设置的各个参数不正确,调整一下

        adjustLimits();

        //生成空的线程池

        pool = new ControlRunnable[maxThreads];

        //启动最小线数线程

        openThreads(minSpareThreads);

        //启动监视线程,监视线程池内部状态

        monitor = new MonitorRunnable(this);

}

(3)      openThreads方法

/**

* 启动指定数量(toOpen)的线程

* 这个方法很是奇怪,这个toOpen并不是本次打开的的线程数

* 而是本次要打开的和以前已经打开的线程数总和

*/

    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;

    }

到这里我们感觉Apache的做法好生奇怪,首先这个toOpen,还有一点,以前我们写连接池时,都时用List作为容器,一般有个当前的空闲线程数,但Apache偏偏用数组作为容器来存放线程,用数组就要维护每种线程(新的,使用的,空闲的)在数组中的下标,若用List这些问题就没了,我们只要getaddremove一下就一切OK,非常方便。因为有了currentThreadsBusyApache的当前的空闲线程数就必须用currentThreadCount- currentThreadsBusy计算得来。这就时我们为什么会看到上面那个奇怪得小循环。但用数组到底有什么好处呢,还是Apache的人是猪头(靠,他们不可能是猪头)?,我们可能发现上面有个常量

 

 

//最大线程数

    public static final int MAX_THREADS = 200;

           也就是说,默认最多池可以有200个线程,就是说有很多线程可能频繁地从池中

            取,放线程,如果用List效率将大打折扣,因此才用了数组

(4)      findControlRunnable方法,取得一个可用线程

private ControlRunnable findControlRunnable() {

        ControlRunnable c=null;

 

 

        if ( stopThePool ) {

            throw new IllegalStateException();

        }

 

 

        //从池中取一个可用的线程.

        synchronized(this) {

            //当前所有的线程都被使用

            while (currentThreadsBusy == currentThreadCount) {

                 //当前的线程数量小于最大线程数

                if (currentThreadCount < maxThreads) {

                      //生成一定数量(minSpareThreads)线程,这一点与

                   //我们做连接池时非常不一样,我们往往只生成一个新连

                   //接,看来Apache的东西真是值得我们学习

                    int toOpen = currentThreadCount +

minSpareThreads;

                    openThreads(toOpen);

                } else {

                    logFull(log, currentThreadCount,

                            maxThreads);

                      //如果所有线程(已到最大数)都被使用,则等待其他线

                   //程释放.

                    try {

                        this.wait();

                    }catch(InterruptedException e) {

                        log.error("Unexpected exception", e);

                    }

                    // Pool was stopped. Get away of the pool.

                    if( stopThePool) {

                        break;

                    }

                }

            }

            // Pool was stopped. Get away of the pool.

            if(0 == currentThreadCount || stopThePool) {

                throw new IllegalStateException();

            }

                   

          

            int pos = currentThreadCount - currentThreadsBusy - 1;

            //经过上面一番折腾,在线程池里终于又有了空闲线程,下面取数

            //组里最后一个线程

            c = pool[pos];

 

 

              //释放当前线程池对该线程的引用

pool[pos] = null;

 

 

             //当然,使用线程的数量也要加1

       currentThreadsBusy++;

 

 

        }

        return c;

}

<
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值