线程池的基本概念
- _threadsStarted:启动的线程数
- _threadsIdle:空闲的线程数
- _lastShrink:记录上次线程结束时间,用于销毁空闲线程
- _threads:使用ConcurrentLinkedQueue来存放线程
- _joinLock:等待线程池结束的锁【不常用】
- _jobs:默认使用BlockingArrayQueue<Runnable>来存放任务队列,当_maxQueued>0的时候会使用ArrayBlockingQueue<Runnable>(_maxQueued)
- _name:线程池的名字
- _maxIdleTimeMs:线程空闲的最大时间
- _maxThreads:最大线程数
- _minThreads:最小线程数
- _maxQueued:任务队列的最大长度,默认-1(无限制即Integer.MAX_VALUE)
- _priority:默认Thread.NORM_PRIORITY,仅在测试环境中使用setThreadsPriority(int priority)【不常用】
- _daemon:是否daemon线程【不常用】
- _maxStopTime:等待线程池结束的最大时间【不常用】
- _detailedDump:是否在调用void dump(Appendable out, String indent)是输出更详细的信息
线程池的常用场景
1)实例化
根据$JETTY_HOME/etc/jetty.xml比如
<Set name="ThreadPool">
<!-- Default queued blocking threadpool -->
<New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<Set name="minThreads">1</Set>
<Set name="maxThreads">3</Set>
<Set name="detailedDump">false</Set>
</New>
</Set>
会分别调用
- setMinThreads(int minThreads)
- 如果已启动的线程小于最小线程数而且线程池已启动,则开启线程startThread(int threads)
- setMaxThreads(int maxThreads)
- setDetailedDump(boolean detailedDump)
此时
线程组_threads为空
任务队列_jobs为null
2)启动doStart()
- _threadsStarted设置为0
- 实例化_jobs为BlockingArrayQueue(默认无限制即Integer.MAX_VALUE)
- 启动minThreads个worker线程
3)提交dispatch(Runnable job)
- 往jobs队列中添加job
- 如果添加成功,检查如果没有空闲线程,或者jobs中等待处理的job个数大于空闲线程 而且此时未达到最大线程数则启动新线程
4)还有几个不太常用的场景就不赘述了
- String dumpThread(long id) //dump单个线程信息
- boolean interruptThread(long id)//中断线程池中某个线程
- void dump(Appendable out, String indent)//dump所有线程
- void join() //等待线程池停止
- void doStop()//停止
线程池中的线程生命周期
1)进入job循环,不断从jobs队列取job
2)如果取不到job退出job循环进入idle循环有一个_threadsIdle变量专门记录worker线程进入idle循环个数
3)如果_maxIdleTimeMs<0(默认60秒),线程阻塞等待jobs中job,一旦取到再次进入job循环,到1)
4)否则检查当前启动线程数是否大于最小线程数,如果是且空闲时间超过_maxIdleTimeMs,则结束该线程
5)否则线程阻塞等待jobs,超时设为_maxIdleTimeMs,如果拿到job再次进入job循环到1),否则到3)
小结
- jetty默认线程池QueuedThreadPool实现较为简单
- 没有什么额外的管理线程来增减线程,线程的增减在运行是自动完成,比如dispatch会添加线程,线程会根据情况自己销毁
- 和外界的常用接口就是dispatch和execute(会调用dispatch)
- 也就是往jobs队列中丢任务
- 某些线程池比如tomcat5或者varnish会将task直接扔给线程而不是队列,如果无空闲线程才会扔到等待队列
- varnish中的线程被唤醒后会优先从等待队列中取任务
- jetty 线程没有所谓的tomcat中的等待队列的概念
注意:
- 如果_maxQueued没有设定即为-1,那么任务队列会为Integer.MAX_VALUE,此时是存在风险的
- _maxIdleTimeMs并不完全是某个线程的空闲时间,很有可能某个线程还没空闲_maxIdleTimeMs就结束掉了,因为jetty的线程池会有一个全局的_lastShrink记录销毁时间,判断是否结束的公式是now-_lastShrink>_maxIdleTimeMs,显然更精确的公式应该是now-$(线程进入idle loop的时间)>_maxIdleTimeMs