簡略引見Java編程中的線程池。本站提示廣大學習愛好者:(簡略引見Java編程中的線程池)文章只能為提供參考,不一定能成為您想要的結果。以下是簡略引見Java編程中的線程池正文
從 Java 5 開端,Java 供給了本身的線程池。線程池就是一個線程的容器,每次只履行額外數目的線程。 java.util.concurrent.ThreadPoolExecutor 就是如許的線程池。它很靈巧,但應用起來也比擬龐雜,本文就對其做一個引見。
起首是結構函數。以最簡略的結構函數為例:
public ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
看起來挺龐雜的。這裡引見一下。
corePoolSize 指的是保存的線程池年夜小。
maximumPoolSize 指的是線程池的最年夜年夜小。
keepAliveTime 指的是余暇線程停止的超不時間。
unit 是一個列舉,表現 keepAliveTime 的單元。
workQueue 表現寄存義務的隊列。
我們可以從線程池的任務進程中懂得這些參數的意義。線程池的任務進程以下:
1、線程池剛創立時,外面沒有一個線程。義務隊列是作為參數傳出去的。不外,就算隊列外面有義務,線程池也不會立時履行它們。
2、當挪用 execute() 辦法添加一個義務時,線程池會做以下斷定:
a. 假如正在運轉的線程數目小於 corePoolSize,那末立時創立線程運轉這個義務;
b. 假如正在運轉的線程數目年夜於或等於 corePoolSize,那末將這個義務放入隊列。
c. 假如這時候候隊列滿了,並且正在運轉的線程數目小於 maximumPoolSize,那末照樣要創立線程運轉這個義務;
d. 假如隊列滿了,並且正在運轉的線程數目年夜於或等於 maximumPoolSize,那末線程池會拋出異常,告知挪用者“我不克不及再接收義務了”。
3、當一個線程完成義務時,它會從隊列中取下一個義務來履行。
4、當一個線程無事可做,跨越必定的時光(keepAliveTime)時,線程池會斷定,假如以後運轉的線程數年夜於 corePoolSize,那末這個線程就被停失落。所以線程池的一切義務完成後,它終究會壓縮到 corePoolSize 的年夜小。
如許的進程解釋,其實不是先參加義務就必定會先履行。假定隊列年夜小為 10,corePoolSize 為 3,maximumPoolSize 為 6,那末當參加 20 個義務時,履行的次序就是如許的:起首履行義務 1、2、3,然前任務 4~13 被放入隊列。這時候候隊列滿了,義務 14、15、16 會被立時履行,而義務 17~20 則會拋出異常。終究次序是:1、2、3、14、15、16、4、5、6、7、8、9、10、11、12、13。上面是一個線程池應用的例子:
public static void main(String[] args) { BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(); ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 1, TimeUnit.DAYS, queue); for (int i = 0; i < 20; i++) { executor.execute(new Runnable() { public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(String.format("thread %d finished", this.hashCode())); } }); } executor.shutdown(); }
對這個例子的解釋以下:
1、BlockingQueue 只是一個接口,經常使用的完成類有 LinkedBlockingQueue 和 ArrayBlockingQueue。用 LinkedBlockingQueue 的利益在於沒有年夜小限制。如許的話,由於隊列不會滿,所以 execute() 不會拋出異常,而線程池中運轉的線程數也永久不會跨越 corePoolSize 個,keepAliveTime 參數也就沒成心義了。
2、shutdown() 辦法不會壅塞。挪用 shutdown() 辦法以後,主線程就立時停止了,而線程池會持續運轉直到一切義務履行完才會停滯。假如不挪用 shutdown() 辦法,那末線程池會一向堅持下去,以便隨時添加新的義務。
到這裡關於這個線程池還只是引見了一小部門。ThreadPoolExecutor 具有很強的可擴大性,不外擴大它的條件是要熟習它的任務方法。前面的文章將會引見若何擴大 ThreadPoolExecutor 類。
ava.util.concurrent.ThreadPoolExecutor 類供給了豐碩的可擴大性。你可以經由過程創立它的子類來自界說它的行動。例如,我願望當每一個義務停止以後打印一條新聞,但我又沒法修正義務對象,那末我可以如許寫:
ThreadPoolExecutor executor = new ThreadPoolExecutor(size, maxSize, 1, TimeUnit.DAYS, queue) { @Override protected void afterExecute(Runnable r, Throwable t) { System.out.println("Task finished."); } };
除 afterExecute 辦法以外,ThreadPoolExecutor 類還有 beforeExecute() 和 terminated() 辦法可以重寫,分離是在義務履行之前和全部線程池停滯以後履行。
除可以添加義務履行前後的舉措以外, ThreadPoolExecutor 還許可你自界說當添加義務掉敗後的履行戰略。你可以挪用線程池的 setRejectedExecutionHandler() 辦法,用自界說的 RejectedExecutionHandler 對象調換現有的戰略。 ThreadPoolExecutor 供給 4 個現有的戰略,分離是:
ThreadPoolExecutor.AbortPolicy:表現謝絕義務並拋出異常
ThreadPoolExecutor.DiscardPolicy:表現謝絕義務但不做任何舉措
ThreadPoolExecutor.CallerRunsPolicy:表現謝絕義務,並在挪用者的線程中直接履行該義務
ThreadPoolExecutor.DiscardOldestPolicy:表現先拋棄義務隊列中的第一個義務,然後把這個義務加進隊列。
這裡是一個例子:
ThreadPoolExecutor executor = new ThreadPoolExecutor(size, maxSize, 1, TimeUnit.DAYS, queue);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
除此以外,你也能夠經由過程完成 RejectedExecutionHandler 接口來編寫本身的戰略。上面是一個例子:
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 1, TimeUnit.SECONDS, queue, new RejectedExecutionHandler() { public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.out.println(String.format("Task %d rejected.", r.hashCode())); } } );