摘要:本人郵箱歡迎轉(zhuǎn)載轉(zhuǎn)載請注明網(wǎng)址代碼已經(jīng)全部托管有需要的同學自行下載引言在之前的例子我們要創(chuàng)建多個線程處理一批任務的時候我是通過創(chuàng)建線程數(shù)組或者使用線程集合來管理的但是這樣做不太好因為這些線程沒有被重復利用所以這里要引入線程池今天我們就講線程
引言本人郵箱:
歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明網(wǎng)址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代碼已經(jīng)全部托管github有需要的同學自行下載
在之前的例子,我們要創(chuàng)建多個線程處理一批任務的時候.我是通過創(chuàng)建線程數(shù)組,或者使用線程集合來管理的.但是這樣做不太好,因為這些線程沒有被重復利用.所以這里要引入線程池,今天我們就講線程池執(zhí)行器ThreadPoolExecutor.
理論首先我們來看一下它的構(gòu)造器:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue
corePoolSize 核心線程數(shù),線程池保留線程的數(shù)量,即使這些線程是空閑.除非設置了allowCoreThreadTimeOut
maximumPoolSize 線程池最大允許的線程數(shù).
keepAliveTime 當當前的線程數(shù)大于核心線程數(shù),那么這些多余的空閑的線程在被終止之前能等待新任務的時間.
unit keepAliveTime時間的單位
workQueue 這個是用來保留將要執(zhí)行的工作隊列.
threadFactory 用于創(chuàng)建新線程的工廠
handler 如果工作隊列(workQueue)滿了,那么這個handler是將會被執(zhí)行.
ThreadPoolExecutor還有幾個可不帶threadFactory或handler慘的構(gòu)造器,說明java提供了一些默認的配置,讓我們看一下.
如果構(gòu)造不帶threadFactory,那么默認使用java.util.concurrent.Executors.DefaultThreadFactory創(chuàng)建出一個新的工廠對象.通過閱讀源代碼,主要是在創(chuàng)建新的線程的時候修改了線程名為pool-全局線程池遞增數(shù)編號-thread-當前線程池線程遞增編號,讓線程改為非守護線程,并設置線程的優(yōu)先級為NORM_PRIORITY.
ok,再看一下handler有什么默認值.
java.util.concurrent.ThreadPoolExecutor.AbortPolicy 這個是默認使用的拒絕策略,如果有要執(zhí)行的任務隊列已滿,且還有任務提交,則直接拋出異常信息
java.util.concurrent.ThreadPoolExecutor.DiscardPolicy 這個是忽略策略,如果有要執(zhí)行的任務隊列已滿,且還有任務提交,則直接忽略掉這個任務,即不拋出異常也不做任何處理.
java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy 忽略最早提交的任務.如果有要執(zhí)行的任務隊列已滿,此時若還有任務提交且線程池還沒有停止,則把隊列中最早提交的任務拋棄掉,然后把當前任務加入隊列中.
java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy 這個是來著不拒策略.如果有要執(zhí)行的任務隊列已滿,此時若還有任務提交且線程池還沒有停止,則直接運行任務的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來了.......
從結(jié)果看出來,可以看出線程是重復被使用的,而且當執(zhí)行的任務超過工作隊列的容量時,線程確實拋出了異常.
例子2 使用忽略策略 DiscardPolicy將RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();改為 RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
運行結(jié)果如下:
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來了.......
現(xiàn)在線程池正確退出了,而且也不拋出異常了,但是超過工作隊列容量的任務全部被忽略了.
例子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來了.......
從以上結(jié)果,我們可以看出除了客戶0到客戶2剛好是3個核心線程被執(zhí)行后,客戶3到客戶7直接被忽略掉了.
例子4 使用來著不拒策略 CallerRunsPolicy同樣講拒絕策略改為RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
運行程序,結(jié)果如下:
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來了.......
結(jié)果,我們可以發(fā)現(xiàn)所有的任務都被執(zhí)行,而且竟然還有兩個是在主線程執(zhí)行的.現(xiàn)在明白我之前說的則直接運行任務的run方法的意思了吧,沒錯是直接調(diào)用run方法,而不是開啟線程去執(zhí)行任務.
例子5 使用自定義的拒絕策略現(xiàn)在我們自己寫一個拒絕策略,要求所有的任務都必須被線程池執(zhí)行,而且都要在線程池中執(zhí)行.
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(); } }
運行結(jié)果:
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.所有任務都被線程池執(zhí)行了.而且我們自定義的拒絕策略也很簡單,就是讓工作隊列調(diào)用put讓其一直等待,直到有可用的容量存放任務.
打賞如果覺得我的文章寫的還過得去的話,有錢就捧個錢場,沒錢給我捧個人場(幫我點贊或推薦一下)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/69962.html
摘要:在并發(fā)量較低的環(huán)境下,線程沖突的概率比較小,自旋的次數(shù)不會很多。比如有三個,每個線程對增加。的核心方法還是通過例子來看假設現(xiàn)在有一個對象,四個線程同時對進行累加操作。 showImg(https://segmentfault.com/img/remote/1460000016012084); 本文首發(fā)于一世流云的專欄:https://segmentfault.com/blog... ...
摘要:當活動線程核心線程非核心線程達到這個數(shù)值后,后續(xù)任務將會根據(jù)來進行拒絕策略處理。線程池工作原則當線程池中線程數(shù)量小于則創(chuàng)建線程,并處理請求。當線程池中的數(shù)量等于最大線程數(shù)時默默丟棄不能執(zhí)行的新加任務,不報任何異常。 spring-cache使用記錄 spring-cache的使用記錄,坑點記錄以及采用的解決方案 深入分析 java 線程池的實現(xiàn)原理 在這篇文章中,作者有條不紊的將 ja...
摘要:本文只介紹中線程池的基本使用,不會過多的涉及到線程池的原理。可緩存線程的線程池創(chuàng)建一個可緩存線程的線程池。首先是從接口繼承到的方法使用該方法即將一個任務交給線程池去執(zhí)行。方法方法的作用是向線程池發(fā)送關(guān)閉的指令。 首先,我們?yōu)槭裁葱枰€程池?讓我們先來了解下什么是 對象池 技術(shù)。某些對象(比如線程,數(shù)據(jù)庫連接等),它們創(chuàng)建的代價是非常大的 —— 相比于一般對象,它們創(chuàng)建消耗的時間和內(nèi)存都...
摘要:本人郵箱歡迎轉(zhuǎn)載轉(zhuǎn)載請注明網(wǎng)址代碼已經(jīng)全部托管有需要的同學自行下載引言前面我們講了那么多有關(guān)線程的知識不知道讀者有沒有想過這么一個問題如果有這么一個比較耗時的任務必須使用線程來執(zhí)行但是在這個任務執(zhí)行完之后我需要得到這個線程的返回值以目前我們 本人郵箱: 歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明網(wǎng)址 http://blog.csdn.net/tianshi_kcogithub: https://github...
摘要:線程的啟動與銷毀都與本地線程同步。操作系統(tǒng)會調(diào)度所有線程并將它們分配給可用的??蚣艿某蓡T主要成員線程池接口接口接口以及工具類。創(chuàng)建單個線程的接口與其實現(xiàn)類用于表示異步計算的結(jié)果。參考書籍并發(fā)編程的藝術(shù)方騰飛魏鵬程曉明著 在java中,直接使用線程來異步的執(zhí)行任務,線程的每次創(chuàng)建與銷毀需要一定的計算機資源開銷。每個任務創(chuàng)建一個線程的話,當任務數(shù)量多的時候,則對應的創(chuàng)建銷毀開銷會消耗大量...
閱讀 2286·2021-11-23 09:51
閱讀 5681·2021-09-22 15:39
閱讀 3355·2021-09-02 15:15
閱讀 3505·2019-08-30 15:54
閱讀 2364·2019-08-30 15:53
閱讀 1404·2019-08-30 14:04
閱讀 2459·2019-08-29 18:33
閱讀 2376·2019-08-29 13:08