摘要:本人郵箱歡迎轉載轉載請注明網址代碼已經全部托管有需要的同學自行下載引言在之前的例子我們要創建多個線程處理一批任務的時候我是通過創建線程數組或者使用線程集合來管理的但是這樣做不太好因為這些線程沒有被重復利用所以這里要引入線程池今天我們就講線程
引言本人郵箱:
歡迎轉載,轉載請注明網址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代碼已經全部托管github有需要的同學自行下載
在之前的例子,我們要創建多個線程處理一批任務的時候.我是通過創建線程數組,或者使用線程集合來管理的.但是這樣做不太好,因為這些線程沒有被重復利用.所以這里要引入線程池,今天我們就講線程池執行器ThreadPoolExecutor.
理論首先我們來看一下它的構造器:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue
corePoolSize 核心線程數,線程池保留線程的數量,即使這些線程是空閑.除非設置了allowCoreThreadTimeOut
maximumPoolSize 線程池最大允許的線程數.
keepAliveTime 當當前的線程數大于核心線程數,那么這些多余的空閑的線程在被終止之前能等待新任務的時間.
unit keepAliveTime時間的單位
workQueue 這個是用來保留將要執行的工作隊列.
threadFactory 用于創建新線程的工廠
handler 如果工作隊列(workQueue)滿了,那么這個handler是將會被執行.
ThreadPoolExecutor還有幾個可不帶threadFactory或handler慘的構造器,說明java提供了一些默認的配置,讓我們看一下.
如果構造不帶threadFactory,那么默認使用java.util.concurrent.Executors.DefaultThreadFactory創建出一個新的工廠對象.通過閱讀源代碼,主要是在創建新的線程的時候修改了線程名為pool-全局線程池遞增數編號-thread-當前線程池線程遞增編號,讓線程改為非守護線程,并設置線程的優先級為NORM_PRIORITY.
ok,再看一下handler有什么默認值.
java.util.concurrent.ThreadPoolExecutor.AbortPolicy 這個是默認使用的拒絕策略,如果有要執行的任務隊列已滿,且還有任務提交,則直接拋出異常信息
java.util.concurrent.ThreadPoolExecutor.DiscardPolicy 這個是忽略策略,如果有要執行的任務隊列已滿,且還有任務提交,則直接忽略掉這個任務,即不拋出異常也不做任何處理.
java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy 忽略最早提交的任務.如果有要執行的任務隊列已滿,此時若還有任務提交且線程池還沒有停止,則把隊列中最早提交的任務拋棄掉,然后把當前任務加入隊列中.
java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy 這個是來著不拒策略.如果有要執行的任務隊列已滿,此時若還有任務提交且線程池還沒有停止,則直接運行任務的run方法.
例子 使用默認的拒絕策略AbortPolicypublic class Demo1 { public static void main(String[] args) { BlockingQueuequeue = new ArrayBlockingQueue (10); RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 3, 0, TimeUnit.SECONDS, queue, handler); for (int i = 0; i < 20; i ++){ final int temp = i; pool.execute(() -> { System.out.println("客戶" + temp + "來了......."); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } }); } pool.shutdown(); } }
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.kco.test17.demo1.Demo1$$Lambda$1/15497079@ca494b rejected from java.util.concurrent.ThreadPoolExecutor@1a4f24f[Running, pool size = 5, active threads = 5, queued tasks = 10, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
at com.kco.test17.demo1.Demo1.main(Demo1.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
pool-1-thread-1客戶0來了.......
pool-1-thread-2客戶1來了.......
pool-1-thread-3客戶2來了.......
pool-1-thread-5客戶14來了.......
pool-1-thread-4客戶13來了.......
pool-1-thread-2客戶3來了.......
pool-1-thread-1客戶4來了.......
pool-1-thread-5客戶5來了.......
pool-1-thread-3客戶6來了.......
pool-1-thread-4客戶7來了.......
pool-1-thread-2客戶9來了.......
pool-1-thread-1客戶8來了.......
pool-1-thread-3客戶10來了.......
pool-1-thread-5客戶11來了.......
pool-1-thread-4客戶12來了.......
從結果看出來,可以看出線程是重復被使用的,而且當執行的任務超過工作隊列的容量時,線程確實拋出了異常.
例子2 使用忽略策略 DiscardPolicy將RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();改為 RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
運行結果如下:
pool-1-thread-1客戶0來了.......
pool-1-thread-3客戶2來了.......
pool-1-thread-4客戶13來了.......
pool-1-thread-5客戶14來了.......
pool-1-thread-3客戶3來了.......
pool-1-thread-4客戶4來了.......
pool-1-thread-1客戶5來了.......
pool-1-thread-5客戶6來了.......
pool-1-thread-2客戶1來了.......
pool-1-thread-3客戶7來了.......
pool-1-thread-4客戶8來了.......
pool-1-thread-5客戶9來了.......
pool-1-thread-1客戶10來了.......
pool-1-thread-2客戶11來了.......
pool-1-thread-4客戶12來了.......
現在線程池正確退出了,而且也不拋出異常了,但是超過工作隊列容量的任務全部被忽略了.
例子3 使用忽略最早任務策略 DiscardOldestPolicyRejectedExecutionHandler改為RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy();
pool-1-thread-1客戶0來了.......
pool-1-thread-2客戶1來了.......
pool-1-thread-3客戶2來了.......
pool-1-thread-5客戶14來了.......
pool-1-thread-4客戶13來了.......
pool-1-thread-4客戶8來了.......
pool-1-thread-1客戶11來了.......
pool-1-thread-5客戶10來了.......
pool-1-thread-3客戶9來了.......
pool-1-thread-2客戶12來了.......
pool-1-thread-1客戶15來了.......
pool-1-thread-4客戶16來了.......
pool-1-thread-5客戶17來了.......
pool-1-thread-2客戶19來了.......
pool-1-thread-3客戶18來了.......
從以上結果,我們可以看出除了客戶0到客戶2剛好是3個核心線程被執行后,客戶3到客戶7直接被忽略掉了.
例子4 使用來著不拒策略 CallerRunsPolicy同樣講拒絕策略改為RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
運行程序,結果如下:
pool-1-thread-1客戶0來了.......
pool-1-thread-2客戶1來了.......
pool-1-thread-3客戶2來了.......
pool-1-thread-4客戶13來了.......
main客戶15來了.......
pool-1-thread-5客戶14來了.......
pool-1-thread-2客戶3來了.......
pool-1-thread-1客戶4來了.......
main客戶18來了.......
pool-1-thread-3客戶5來了.......
pool-1-thread-4客戶7來了.......
pool-1-thread-5客戶6來了.......
pool-1-thread-5客戶8來了.......
pool-1-thread-1客戶9來了.......
pool-1-thread-4客戶10來了.......
pool-1-thread-3客戶12來了.......
pool-1-thread-2客戶11來了.......
pool-1-thread-1客戶16來了.......
pool-1-thread-5客戶19來了.......
pool-1-thread-3客戶17來了.......
結果,我們可以發現所有的任務都被執行,而且竟然還有兩個是在主線程執行的.現在明白我之前說的則直接運行任務的run方法的意思了吧,沒錯是直接調用run方法,而不是開啟線程去執行任務.
例子5 使用自定義的拒絕策略現在我們自己寫一個拒絕策略,要求所有的任務都必須被線程池執行,而且都要在線程池中執行.
public class Demo5 { public static void main(String[] args) { BlockingQueuequeue = new ArrayBlockingQueue (10); RejectedExecutionHandler handler = new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { if (!executor.isShutdown()){ try { executor.getQueue().put(r); } catch (InterruptedException e) { e.printStackTrace(); } } } }; ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 5, 0, TimeUnit.SECONDS, queue, handler); for (int i = 0; i < 20; i ++){ final int temp = i; pool.execute(() -> { String name = Thread.currentThread().getName(); System.out.println(name + "客戶" + temp + "來了......."); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } }); } pool.shutdown(); } }
運行結果:
pool-1-thread-1客戶0來了.......
pool-1-thread-3客戶2來了.......
pool-1-thread-5客戶14來了.......
pool-1-thread-4客戶13來了.......
pool-1-thread-2客戶1來了.......
pool-1-thread-1客戶3來了.......
pool-1-thread-3客戶4來了.......
pool-1-thread-5客戶5來了.......
pool-1-thread-2客戶6來了.......
pool-1-thread-4客戶7來了.......
pool-1-thread-1客戶8來了.......
pool-1-thread-3客戶9來了.......
pool-1-thread-5客戶10來了.......
pool-1-thread-4客戶11來了.......
pool-1-thread-2客戶12來了.......
pool-1-thread-1客戶15來了.......
pool-1-thread-3客戶16來了.......
pool-1-thread-5客戶17來了.......
pool-1-thread-4客戶19來了.......
pool-1-thread-2客戶18來了.......
ok.所有任務都被線程池執行了.而且我們自定義的拒絕策略也很簡單,就是讓工作隊列調用put讓其一直等待,直到有可用的容量存放任務.
打賞如果覺得我的文章寫的還過得去的話,有錢就捧個錢場,沒錢給我捧個人場(幫我點贊或推薦一下)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69962.html
摘要:在并發量較低的環境下,線程沖突的概率比較小,自旋的次數不會很多。比如有三個,每個線程對增加。的核心方法還是通過例子來看假設現在有一個對象,四個線程同時對進行累加操作。 showImg(https://segmentfault.com/img/remote/1460000016012084); 本文首發于一世流云的專欄:https://segmentfault.com/blog... ...
摘要:當活動線程核心線程非核心線程達到這個數值后,后續任務將會根據來進行拒絕策略處理。線程池工作原則當線程池中線程數量小于則創建線程,并處理請求。當線程池中的數量等于最大線程數時默默丟棄不能執行的新加任務,不報任何異常。 spring-cache使用記錄 spring-cache的使用記錄,坑點記錄以及采用的解決方案 深入分析 java 線程池的實現原理 在這篇文章中,作者有條不紊的將 ja...
摘要:本文只介紹中線程池的基本使用,不會過多的涉及到線程池的原理。可緩存線程的線程池創建一個可緩存線程的線程池。首先是從接口繼承到的方法使用該方法即將一個任務交給線程池去執行。方法方法的作用是向線程池發送關閉的指令。 首先,我們為什么需要線程池?讓我們先來了解下什么是 對象池 技術。某些對象(比如線程,數據庫連接等),它們創建的代價是非常大的 —— 相比于一般對象,它們創建消耗的時間和內存都...
摘要:本人郵箱歡迎轉載轉載請注明網址代碼已經全部托管有需要的同學自行下載引言前面我們講了那么多有關線程的知識不知道讀者有沒有想過這么一個問題如果有這么一個比較耗時的任務必須使用線程來執行但是在這個任務執行完之后我需要得到這個線程的返回值以目前我們 本人郵箱: 歡迎轉載,轉載請注明網址 http://blog.csdn.net/tianshi_kcogithub: https://github...
摘要:線程的啟動與銷毀都與本地線程同步。操作系統會調度所有線程并將它們分配給可用的。框架的成員主要成員線程池接口接口接口以及工具類。創建單個線程的接口與其實現類用于表示異步計算的結果。參考書籍并發編程的藝術方騰飛魏鵬程曉明著 在java中,直接使用線程來異步的執行任務,線程的每次創建與銷毀需要一定的計算機資源開銷。每個任務創建一個線程的話,當任務數量多的時候,則對應的創建銷毀開銷會消耗大量...
閱讀 2269·2021-11-23 09:51
閱讀 5657·2021-09-22 15:39
閱讀 3343·2021-09-02 15:15
閱讀 3493·2019-08-30 15:54
閱讀 2355·2019-08-30 15:53
閱讀 1397·2019-08-30 14:04
閱讀 2446·2019-08-29 18:33
閱讀 2364·2019-08-29 13:08