線程池的基本概念
- _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