前言
一直以來對線程池的概念都挺模糊的,想不明白線程池要如何實現,今天難得周末,就開始查閱資料,研究了一下jdk中的線程池實現,終於解開了我長久以來的疑惑,本文參考文章來自網絡,原文連接如下:
http://www.cnblogs.com/dolphin0520/p/3932921.html
參考連接針對jdk6,本文針對jdk8
疑惑
和線程池類似的有一個概念叫連接池,在數據庫連接中使用的非常多,連接池比較好理解,一般來說就是一個連接建立完成之后不去關閉它,需要的時候就看獲取這個連接的對象並給它的輸入流寫數據,並從輸出流讀取響應結果,但是在線程中,一旦某個線程的run方法運行結束之后,線程也就結束了,因此和連接池有很大的不同,這也給我留下了幾個疑惑:
- 如何復用一個線程?
- 多個線程如何管理?
- 如何知道某個線程是目前正在運行還是在等待任務?
今天看過jdk中對線程池的實現,才真正明白,線程池和連接池是有很大不同的,使用上也完全不一樣。
- 連接池是每次需要時候的時候,從池里取出一個連接給我們,我們再使用這個連接來交換數據,而線程池並不是在使用的時候從池里取出一個線程對象給我們使用,而是將我們的任務交給線程池,由線程池自己調度任務決定什么時候執行這個任務。
- 連接池的連接用完之后,會直接放到池內,等待下一個請求連接,而線程池的線程一旦運行完,線程也就結束了,因此不存在放回池內的操作。
- 一個連接池要持有一定數量的連接,只要保證持有這些未關閉的連接的對象即可,而線程池要持有一定數量的線程,必須保證持有的線程的run方法不會運行結束。
了解了線程池和連接池的區別之后,我們就可以知道,雖然名字很像,但是實際上這兩者在原理和概念上是完全不一樣的。
jdk1.5以后,新增了一個並發包java.concurrent
,這個包里就包含了線程池的實現,最核心的實現類是java.util.concurrent.ThreadPoolExecutor
。
實際上jdk從1.5到1.8,
java.util.concurrent.ThreadPoolExecutor
已經經過多次重構了,1.6和1.8在實現上已經有了很大的不同了,本文針對的是jdk8中的實現。
jdk的線程池實現
我們來看一下jdk中的線程池是如何實現的。
首先要先了解一下類結構,如下圖:
類結構
最頂層的接口是java.util.concurrent.Executor
:
public interface Executor { void execute(Runnable command); }
只有一個接口,傳入一個Runnable對象,稱為指令,線程池就會幫你執行這個指令。
它的一級子接口是java.util.concurrent.ExecutorService
:
public interface ExecutorService extends Executor { void shutdown(); List<Runnable> shutdownNow(); boolean isShutdown(); boolean isTerminated(); boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task); <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException; <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException; <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException