線程池中的一些細節

線程池的工作原理

我認爲線程池它就是一個調度任務的工具。

衆所周知在初始化線程池會給定線程池的大小,假設現在我們有 1000 個線程任務需要運行,而線程池的大小爲 10,20 個線程來調度這1000個任務。

而這裏的 10~20 個線程最後會由線程池封裝爲 ThreadPoolExecutor.Worker 對象,而這個 Worker 是實現了 Runnable 接口的,所以他自己本身就是一個線程。

深入分析

ExecutorService executorService =  new ThreadPoolExecutor(2,2,0L,TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(2));

這裏我們來做一個模擬,創建了一個核心線程、最大線程數、阻塞隊列都爲2的線程池。

這裏假設線程池已經完成了預熱,也就是線程池內部已經創建好了兩個線程 Worker

當我們往一個線程池丟一個任務會發生什麼事呢?

  • 第一步是生產者,也就是任務提供者他執行了一個 execute() 方法,本質上就是往這個內部隊列裏放了一個任務。
  • 之前已經創建好了的 Worker 線程會執行一個 while 循環 ---> 不停的從這個內部隊列裏獲取任務。(這一步是競爭的關係,都會搶着從隊列裏獲取任務,由這個隊列內部實現了線程安全。)
  • 獲取得到一個任務後,其實也就是拿到了一個 Runnable 對象(也就是 execute(Runnable task) 這裏所提交的任務),接着執行這個 Runnable 的 run() 方法,而不是 start(),這點需要注意後文分析原因。

爲什是 run() 而不是 start()

爲什麼線程池在調度的時候執行的是 Runnable 的 run() 方法,而不是 start() 方法呢?

網上大牛講的都是隻有執行了 start() 方法後操作系統纔會給我們創建一個獨立的線程來運行,而 run() 方法只是一個普通的方法調用。

而在線程池這個場景中卻恰好就是要利用它只是一個普通方法調用。

假設這裏是調用的 Runnable 的 start 方法,那會發生什麼事情。

如果我們往一個核心、最大線程數爲 2 的線程池裏丟了 1000 個任務,那麼它會額外的創建 1000 個線程,同時每個任務都是異步執行的,一下子就執行完畢了

從而沒法做到由這兩個 Worker 線程來調度這 1000 個任務,而只有當做一個同步阻塞的 run() 方法調用時才能滿足這個要求。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章