public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(10); service.submit(() -> System.out.println("Hello ")); System.out.println("World"); } 複製代碼
呵呵,執行結果誰都知道,顯而易見架構
可是小老弟,有沒有發現這個程序一直都沒有結束源碼分析
呢?明明這個任務都已經跑完了呀~學習
開始了嗎?很差意思已經結束了,嘻嘻,大過年的不賣關子,咱們直接公佈答案,形成不退出的緣由是這樣:this
submit
操做會建立 Worker
線程(負責去拿任務處理),該線程裏寫了一個死循環,因此這個 Worker
線程不會死Worker
線程在建立的時候,被設置成了 非守護線程 , thread.setDaemon(false)
JDK1.5
的時候,就規定了當全部非守護線程退出時, JVM
纔會退出, Main
方法主線程和 Worker
線程都是非守護線程,因此不會死。下面咱們會就上面幾個問題,每個問題進行源碼分析,感興趣的看官老爺能夠繼續,看看又不會掉髮(逃spa
夢開始的地方先從初始化開始線程
//該方法利用多臺實例化了一個ThreadPoolExecutor線程池,該線程池繼承了一個抽象類AbstractExecutorService ExecutorService service = Executors.newFixedThreadPool(10); //調用了ThreadPoolExecutor.submit方法也就是父類的AbstractExecutorService.submit,該方法內部會去調用execute()方法 service.submit(() -> System.out.println("Hello ")); 複製代碼
因而咱們定位到 ThreadPoolExecutor
類的 execute
方法,我截取了部分以下, 注意代碼中我打註釋的地方code
public void execute(Runnable command) { ... //若是工做線程尚未超過核心線程數 if (workerCountOf(c) < corePoolSize) { //去添加工做線程 if (addWorker(command, true)) return; } ... 複製代碼
線程池把每個運行任務的工做線程抽象成了 Worker
,咱們定位到內部 addWorker
方法視頻
... //新建一個Worker w = new Worker(firstTask); final Thread t = w.thread; if (t != null) { //下面的操做是將線程添加到工做線程集合裏 final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { int rs = runStateOf(ctl.get()); if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { if (t.isAlive()) // precheck that t is startable throw new IllegalThreadStateException(); workers.add(w); int s = workers.size(); if (s > largestPoolSize) largestPoolSize = s; workerAdded = true; } } finally { mainLock.unlock(); } //若是添加成功的話 if (workerAdded) { //把工做線程跑起來 t.start(); workerStarted = true; } } } finally { if (! workerStarted) addWorkerFailed(w); } return workerStarted; 複製代碼
這時候一個工做線程也就跑起來了,能夠去執行任務了,咱們定位到 ThreadPoolExecutor
的內部類 Worker
的 run
方法裏blog
//該類調用了runWorker方法 public void run() { runWorker(this); } 複製代碼 final void runWorker(Worker w) { Thread wt = Thread.currentThread(); Runnable task = w.firstTask; w.firstTask = null; w.unlock(); // allow interrupts boolean completedAbruptly = true; try { //主要看這個while,會看這個Worker有沒有任務,若是沒有就會去取,這裏是一個死循環,而後咱們定位到getTask()方法,看他是怎麼取任務的 while (task != null || (task = getTask()) != null) { w.lock(); if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) wt.interrupt(); ... } 複製代碼
這裏解釋了,工做線程其實不會死(超時時間不在本期範圍內),咱們繼續定位到內部的 getTask()
方法,看他是怎麼取任務的繼承
private Runnable getTask() { ... //有沒有設置核心線程超時時間(默認沒有)當前工做的線程數大於了線程池的核心線城市 boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; ... try { Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : //調用workQueue的Take方法,WorkQueue默認是一個BlockingQueue,因此調用take方法會致使當前工做線程阻塞掉,指到拿到 workQueue.take(); //若是拿到任務就返回 if (r != null) return r; timedOut = true; ... 複製代碼
這裏想說的有兩點:
BlockingQueue
的 take()
拿不到任務會阻塞首先咱們來到 ThreadPoolExecutor
的構造方法裏
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); } 複製代碼
構造器裏傳入了一個 ThreadFactory
也就是 Executors.defaultThreadFactory()
,用來產生工做線程,一步一步的點進去咱們會定位到 Executors
內部類 DefaultThreadFactory
的 newThread
方法在此我向你們推薦一個架構學習交流裙。交流學習裙號:687810532,裏面會分享一些資深架構師錄製的視頻錄像
public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); //關鍵代碼是這裏,把線程設置成了非守護線程 if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } 複製代碼
而後咱們看 ThreadPoolExector
方法去 new Worker()的時候
Worker(Runnable firstTask) { setState(-1); // inhibit interrupts until runWorker this.firstTask = firstTask; //這裏的ThreadPool,就是上面提到的那個生產非守護線程的線程工廠 this.thread = getThreadFactory().newThread(this); } 複製代碼
看上面的 註釋下面的內容 ,爲何是非守護線程就真相大白了。