線程池執行器 - 1

“普通程序員遲早會意識到他們有許多小任務需要不時執行。”

“如果你正在編寫遊戲,那麼它就是各個角色執行的動作。”

“如果你正在編寫一個網絡服務器,那麼它就是來自用戶的不同命令:上傳照片、將其轉碼為所需格式、應用所需模板等。”

“遲早,所有大任務都會分解成一組小的、可管理的任務。”

“因此,在這種情況下,一個微妙的問題出現了:你應該如何管理它們?如果你需要在一分鐘內執行數百個任務怎麼辦?為每個任務創建一個線程沒有多大意義。Java 機器為每個線程分配相當多的資源。”

“換句話說,創建和銷毀線程可能比任務本身花費更多的時間和資源。”

“Java 的創造者想出了一個優雅的解決方案來解決這個問題:ThreadPoolExecutor

ThreadPoolExecutor是一個包含兩個東西的類:”

A) 任務隊列,您可以在程序中出現任務時將其添加到其中。

B)一個線程池,它是一組執行這些任務的線程。

“更重要的是,一旦任務完成,線程就不會被銷毀。相反,它們會進入休眠狀態,以便在新任務出現時立即準備開始。”

“創建ThreadPoolExecutor時,您可以設置要創建的最大線程數和可以排隊的最大任務數。換句話說,您可以將線程數限制為 10,例如,排隊任務到 100。”

“這就是ThreadPoolExecutor 的工作原理:”

1) 當你添加一個新任務時,它被放在隊列的末尾。

2) 如果隊列已滿,則拋出異常。

3) 完成一個任務後,每個線程從隊列中取出下一個任務並開始執行它。

4)如果隊列中沒有任務,則線程進入休眠狀態,直到有新任務加入。

“我們限制工作線程數量的方法的優勢在於,我們擁有的線程越多,它們之間的干擾就越大。擁有 5-10 個工作線程和一長串任務比擁有 5-10 個工作線程和長任務隊列更有效為激增的任務創建 100 個線程,這些線程將相互競爭資源:內存、處理器時間、數據庫訪問等。”

“這是ThreadPoolExecutor的一個例子:”

例子
ExecutorService service = Executors.newFixedThreadPool(2);

for(int i = 0; i < 10; i++)
{
 service.submit(new Runnable() {
    public void run()
    {
     // Here we download something big from the Internet.
    }
 });
}

“呃,我沒看到……”

“調用 newFixedThreadPool 方法時會創建一個ThreadPoolExecutor對象。”

因此,它非常易於使用。一旦您使用 submit 方法向它添加任務,它就會:

A) 喚醒休眠線程(如果有的話)來執行任務。

B) 如果沒有等待線程,則它會為該任務創建一個新線程。

C) 如果達到最大線程數,則它只是將任務放在隊列的末尾。

“我特意在示例中加入了 «這裡我們從互聯網上下載了一些大東西»。如果我們有 100 個任務 «從互聯網上下載一些大東西»,那麼同時運行很多它們就沒有意義了——我們”將受到我們 Internet 連接的帶寬限制的阻礙。在這種情況下,幾個線程應該足夠了。這就是您在上面的示例中看到的:”

ExecutorService service = Executors.newFixedThreadPool(2);

“事實證明,處理一堆任務並沒有那麼困難。”

“是的。比你想像的更容易。但金會告訴你的。”