詳解Java線程池的使用(7種創(chuàng)建方法)
線程池的創(chuàng)建?法總共有 7 種,但總體來(lái)說(shuō)可分為 2 類:
1. 通過(guò) ThreadPoolExecutor 創(chuàng)建的線程池;
2. 通過(guò) Executors 創(chuàng)建的線程池。
線程池的創(chuàng)建?式總共包含以下 7 種(其中 6 種是通過(guò) Executors 創(chuàng)建的, 1 種是通過(guò) ThreadPoolExecutor 創(chuàng)建的):
1. Executors.newFixedThreadPool:創(chuàng)建?個(gè)固定??的線程池,可控制并發(fā)的線程數(shù),超出的線程會(huì)在隊(duì)列中等待;
2. Executors.newCachedThreadPool:創(chuàng)建?個(gè)可緩存的線程池,若線程數(shù)超過(guò)處理所需,緩存?段時(shí)間后會(huì)回收,若線程數(shù)不夠,則新建線程;
3. Executors.newSingleThreadExecutor:創(chuàng)建單個(gè)線程數(shù)的線程池,它可以保證先進(jìn)先出的執(zhí)?順序;
4. Executors.newScheduledThreadPool:創(chuàng)建?個(gè)可以執(zhí)?延遲任務(wù)的線程池;
5. Executors.newSingleThreadScheduledExecutor:創(chuàng)建?個(gè)單線程的可以執(zhí)?延遲任務(wù)的線程池;
6. Executors.newWorkStealingPool:創(chuàng)建?個(gè)搶占式執(zhí)?的線程池(任務(wù)執(zhí)?順序不確定)【JDK1.8 添加】。
7. ThreadPoolExecutor:最原始的創(chuàng)建線程池的?式,它包含了 7 個(gè)參數(shù)可供設(shè)置,后?會(huì)詳細(xì)講。
1. 固定數(shù)量的線程池
public class ThreadPoolDemo3 { public static void main(String[] args) { ExecutorService threadPool = Executors.newFixedThreadPool(2); //添加任務(wù)方式 1 threadPool.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }); //添加任務(wù)方式2 threadPool.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }); } } 輸出: pool-1-thread-1 pool-1-thread-2
a. 線程池返回結(jié)果
public class ThreadPoolDemo4 { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService threadPool = Executors.newFixedThreadPool(2); //執(zhí)行任務(wù) Future<Integer> result = threadPool.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { int num = new Random().nextInt(10); System.out.println("隨機(jī)數(shù)" + num); return num; } }); //打印線程池返回方式 System.out.println("返回結(jié)果:" + result.get()); } } 輸出 隨機(jī)數(shù)8 返回結(jié)果:8
使用submit可以執(zhí)行有返回值的任務(wù)或者是無(wú)返回值的任務(wù);而execute只能執(zhí)行不帶返回值的任務(wù)。
b. ?定義線程池名稱或優(yōu)先級(jí)
public class ThreadPoolDemo5 { public static void main(String[] args) throws ExecutionException, InterruptedException { // 創(chuàng)建線程工廠 ThreadFactory threadFactory = new ThreadFactory() { @Override public Thread newThread(Runnable r) { //?。。。。。。∫欢ㄒ⒁猓阂讶蝿?wù)Runnable設(shè)置給新創(chuàng)建的線程 Thread thread = new Thread(r); //設(shè)置線程的命名規(guī)則 thread.setName("我的線程" + r.hashCode()); //設(shè)置線程的優(yōu)先級(jí) thread.setPriority(Thread.MAX_PRIORITY); return thread; } }; ExecutorService threadPool = Executors.newFixedThreadPool(2,threadFactory); //執(zhí)行任務(wù)1 Future<Integer> result = threadPool.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { int num = new Random().nextInt(10); System.out.println(Thread.currentThread().getPriority() + ", 隨機(jī)數(shù):" + num); return num; } }); //打印線程池返回結(jié)果 System.out.println("返回結(jié)果:" + result.get()); } }
提供的功能:
1. 設(shè)置(線程池中)線程的命名規(guī)則。
2. 設(shè)置線程的優(yōu)先級(jí)。
3. 設(shè)置線程分組。
4. 設(shè)置線程類型(用戶線程、守護(hù)線程)。
2. 帶緩存的線程池
public class ThreadPoolDemo6 { public static void main(String[] args) { //創(chuàng)建線程池 ExecutorService service = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { int finalI = i; service.submit(() -> { System.out.println("i : " + finalI + "|線程名稱:" + Thread.currentThread().getName()); }); } } } 輸出 i : 1|線程名稱:pool-1-thread-2 i : 4|線程名稱:pool-1-thread-5 i : 3|線程名稱:pool-1-thread-4 i : 5|線程名稱:pool-1-thread-6 i : 0|線程名稱:pool-1-thread-1 i : 2|線程名稱:pool-1-thread-3 i : 6|線程名稱:pool-1-thread-7 i : 7|線程名稱:pool-1-thread-8 i : 8|線程名稱:pool-1-thread-9 i : 9|線程名稱:pool-1-thread-1
優(yōu)點(diǎn):線程池會(huì)根據(jù)任務(wù)數(shù)量創(chuàng)建線程池,并且在一定時(shí)間內(nèi)可以重復(fù)使用這些線程,產(chǎn)生相應(yīng)的線程池。
缺點(diǎn):適用于短時(shí)間有大量任務(wù)的場(chǎng)景,它的缺點(diǎn)是可能會(huì)占用很多的資源。
3. 執(zhí)?定時(shí)任務(wù) a. 延遲執(zhí)?(?次)
public class ThreadPoolDemo7 { public static void main(String[] args) { //創(chuàng)建線程池 ScheduledExecutorService service = Executors.newScheduledThreadPool(5); System.out.println("添加任務(wù)的時(shí)間:" + LocalDateTime.now()); //執(zhí)行定時(shí)任務(wù)(延遲3s執(zhí)行)只執(zhí)行一次 service.schedule(new Runnable() { @Override public void run() { System.out.println("執(zhí)行子任務(wù):" + LocalDateTime.now()); } },3, TimeUnit.SECONDS); } } 輸出 添加任務(wù)的時(shí)間:2022-04-13T14:19:39.983 執(zhí)行子任務(wù):2022-04-13T14:19:42.987
b. 固定頻率執(zhí)?
public class ThreadPoolDemo8 { public static void main(String[] args) { //創(chuàng)建線程池 ScheduledExecutorService service = Executors.newScheduledThreadPool(5); System.out.println("添加任務(wù)時(shí)間:" + LocalDateTime.now()); //2s之后開(kāi)始執(zhí)行定時(shí)任務(wù),定時(shí)任務(wù)每隔4s執(zhí)行一次 service.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("執(zhí)行任務(wù):" + LocalDateTime.now()); } },2,4, TimeUnit.SECONDS); } } 輸出 添加任務(wù)時(shí)間:2022-04-13T14:24:38.810 執(zhí)行任務(wù):2022-04-13T14:24:40.814 執(zhí)行任務(wù):2022-04-13T14:24:44.814 執(zhí)行任務(wù):2022-04-13T14:24:48.813 執(zhí)行任務(wù):2022-04-13T14:24:52.815 執(zhí)行任務(wù):2022-04-13T14:24:56.813 執(zhí)行任務(wù):2022-04-13T14:25:00.813 執(zhí)行任務(wù):2022-04-13T14:25:04.814 執(zhí)行任務(wù):2022-04-13T14:25:08.813 ... ... ... ... 執(zhí)行任務(wù):2022-04-13T14:26:44.814 執(zhí)行任務(wù):2022-04-13T14:26:48.813
注意事項(xiàng):
public class ThreadPoolDemo9 { public static void main(String[] args) { //創(chuàng)建線程池 ScheduledExecutorService service = Executors.newScheduledThreadPool(5); System.out.println("添加任務(wù)時(shí)間:" + LocalDateTime.now()); service.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("執(zhí)行任務(wù): " + LocalDateTime.now()); try { Thread.sleep(5 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } } },2,4, TimeUnit.SECONDS); } } 輸出 添加任務(wù)時(shí)間:2022-04-13T14:33:34.551 執(zhí)行任務(wù): 2022-04-13T14:33:36.556 執(zhí)行任務(wù): 2022-04-13T14:33:41.557 執(zhí)行任務(wù): 2022-04-13T14:33:46.559 執(zhí)行任務(wù): 2022-04-13T14:33:51.561 執(zhí)行任務(wù): 2022-04-13T14:33:56.562 執(zhí)行任務(wù): 2022-04-13T14:34:01.564 執(zhí)行任務(wù): 2022-04-13T14:34:06.566 執(zhí)行任務(wù): 2022-04-13T14:34:11.566 執(zhí)行任務(wù): 2022-04-13T14:34:16.567 執(zhí)行任務(wù): 2022-04-13T14:34:21.570 執(zhí)行任務(wù): 2022-04-13T14:34:26.570 ... ....
c. scheduleAtFixedRate VS scheduleWithFixedDelay
scheduleAtFixedRate 是以上?次任務(wù)的開(kāi)始時(shí)間,作為下次定時(shí)任務(wù)的參考時(shí)間的(參考時(shí)間+延遲任務(wù)=任務(wù)執(zhí)?)。 scheduleWithFixedDelay 是以上?次任務(wù)的結(jié)束時(shí)間,作為下次定時(shí)任務(wù)的參考時(shí)間的。
public class ThreadPoolDemo10 { public static void main(String[] args) { //創(chuàng)建線程池 ScheduledExecutorService service = Executors.newScheduledThreadPool(5); System.out.println("添加任務(wù)時(shí)間:" + LocalDateTime.now()); //2s之后開(kāi)始執(zhí)行定時(shí)任務(wù),定時(shí)任務(wù)每隔4s執(zhí)行一次 service.scheduleWithFixedDelay(new Runnable() { @Override public void run() { System.out.println("執(zhí)行任務(wù):" + LocalDateTime.now()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }, 2, 4, TimeUnit.SECONDS); } } 輸出 添加任務(wù)時(shí)間:2022-04-13T14:46:02.871 執(zhí)行任務(wù):2022-04-13T14:46:04.876 執(zhí)行任務(wù):2022-04-13T14:46:09.878 執(zhí)行任務(wù):2022-04-13T14:46:14.880 執(zhí)行任務(wù):2022-04-13T14:46:19.883 執(zhí)行任務(wù):2022-04-13T14:46:24.885 執(zhí)行任務(wù):2022-04-13T14:46:29.888 執(zhí)行任務(wù):2022-04-13T14:46:34.888 執(zhí)行任務(wù):2022-04-13T14:46:39.891 執(zhí)行任務(wù):2022-04-13T14:46:44.893 執(zhí)行任務(wù):2022-04-13T14:46:49.895 執(zhí)行任務(wù):2022-04-13T14:46:54.897 執(zhí)行任務(wù):2022-04-13T14:46:59.900 執(zhí)行任務(wù):2022-04-13T14:47:04.901 ... ...
4. 定時(shí)任務(wù)單線程
public class ThreadPoolDemo11 { public static void main(String[] args) { ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); System.out.println("添加任務(wù)的時(shí)間:" + LocalDateTime.now()); service.schedule(new Runnable() { @Override public void run() { System.out.println("執(zhí)行時(shí)間:" + LocalDateTime.now()); } },2, TimeUnit.SECONDS ); } } 輸出 添加任務(wù)的時(shí)間:2022-04-13T15:06:38.100 執(zhí)行時(shí)間:2022-04-13T15:06:40.106
5. 單線程線程池
public class ThreadPoolDemo12 { public static void main(String[] args) { ExecutorService service = Executors.newSingleThreadScheduledExecutor(); for (int i = 0; i < 10; i++) { service.submit(new Runnable() { @Override public void run() { System.out.println("線程名:" + Thread.currentThread().getName()); } }); } } } 輸出 線程名:pool-1-thread-1 線程名:pool-1-thread-1 線程名:pool-1-thread-1 線程名:pool-1-thread-1 線程名:pool-1-thread-1 線程名:pool-1-thread-1 線程名:pool-1-thread-1 線程名:pool-1-thread-1 線程名:pool-1-thread-1 線程名:pool-1-thread-1
(MS) 為什么不直接用線程?
單線程的線程池又什么意義?
1. 復(fù)用線程。
2. 單線程的線程池提供了任務(wù)隊(duì)列和拒絕策略(當(dāng)任務(wù)隊(duì)列滿了之后(Integer.MAX_VALUE),新來(lái)的任務(wù)就會(huì)拒絕策略)
6. 根據(jù)當(dāng)前CPU?成線程池
public class ThreadPoolDemo13 { public static void main(String[] args) { ExecutorService service = Executors.newWorkStealingPool(); for (int i = 0; i < 10; i++) { service.submit(() -> { System.out.println("線程名" + Thread.currentThread().getName()); }); while(!service.isTerminated()) { } } } } 輸出 線程名ForkJoinPool-1-worker-1
7. ThreadPoolExecutor
(1). Executors ?動(dòng)創(chuàng)建線程池可能存在的問(wèn)題
a. OOM 代碼演示
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolDemo54 { static class MyOOMClass { // 1M 空間(M KB Byte) private byte[] bytes = new byte[1 * 1024 * 1024]; } public static void main(String[] args) throws InterruptedException { Thread.sleep(15 * 1000); ExecutorService service = Executors.newCachedThreadPool(); Object[] objects = new Object[15]; for (int i = 0; i < 15; i++) { final int finalI = i; service.execute(new Runnable() { @Override public void run() { try { Thread.sleep(finalI * 200); } catch (InterruptedException e) { e.printStackTrace(); } MyOOMClass myOOMClass = new MyOOMClass(); objects[finalI] = myOOMClass; System.out.println("任務(wù):" + finalI); } }); } } }
執(zhí)行結(jié)果:
b. 關(guān)于參數(shù)設(shè)置
-XX:標(biāo)準(zhǔn)設(shè)置,所有 HotSpot 都?持的參數(shù)。 -X:?標(biāo)準(zhǔn)設(shè)置,特定的 HotSpot 才?持的參數(shù)。 -D:程序參數(shù)設(shè)置,-D參數(shù)=value,程序中使?:System.getProperty("獲取")。
mx 是 memory max 的簡(jiǎn)稱
(2). ThreadPoolExecutor 使?
a. ThreadPoolExecutor 參數(shù)說(shuō)明
b. 線程池執(zhí)?流程
c. 執(zhí)?流程驗(yàn)證
<MS>
線程池的重要執(zhí)行節(jié)點(diǎn):
1. 當(dāng)任務(wù)來(lái)了之后,判斷線程池中實(shí)際線程數(shù)是否小于核心線程數(shù),如果小于就直接創(chuàng)建并執(zhí)行任務(wù)。
2. 當(dāng)實(shí)際線程數(shù)大于核心線程數(shù)(正式員工),他就會(huì)判斷任務(wù)隊(duì)列是否已滿,如果未滿就將任務(wù)存放隊(duì)列即可。
3. 判斷線程池的實(shí)際線程數(shù)是否大于最大線程數(shù)(正式員工 + 臨時(shí)員工),如果小于最大線程數(shù),直接創(chuàng)建線程執(zhí)行任務(wù);實(shí)際線程數(shù)已經(jīng)等于最大線程數(shù),則會(huì)直接執(zhí)行拒絕策略。
d. 拒絕策略
(4種 JDK 提供的拒絕策略 + 1 種 自定義拒絕策略)
Java ?帶的拒絕策略,CallerRunsPolicy:
public class ThreadPoolDemo14 { public static void main(String[] args) { ThreadFactory factory = new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); return thread; } }; // 手動(dòng)創(chuàng)建線程池 ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 100, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1), new ThreadPoolExecutor.CallerRunsPolicy()); for (int i = 0; i < 4; i++) { int finalI = i; executor.submit(() -> { System.out.println(Thread.currentThread().getName() + "執(zhí)行任務(wù):" + finalI); }); } //終止線程 executor.shutdown(); } } 輸出 main執(zhí)行任務(wù):2 pool-1-thread-1執(zhí)行任務(wù):0 main執(zhí)行任務(wù):3 pool-1-thread-1執(zhí)行任務(wù):1
?定義拒絕策略:
線程狀態(tài)
shutdown 執(zhí)?時(shí)線程池終?接收新任務(wù),并且會(huì)將任務(wù)隊(duì)列中的任務(wù)處理完; shutdownNow 執(zhí)?時(shí)線程池終?接收新任務(wù),并且會(huì)給終?執(zhí)?任務(wù)隊(duì)列中的任務(wù)。
1. RUNNING:這個(gè)沒(méi)什么好說(shuō)的,這是最正常的狀態(tài):接受新的任務(wù),處理等待隊(duì)列中的任務(wù); SHUTDOWN:不接受新的任務(wù)提交,但是會(huì)繼續(xù)處理等待隊(duì)列中的任務(wù); 2. STOP:不接受新的任務(wù)提交,不再處理等待隊(duì)列中的任務(wù),中斷正在執(zhí)?任務(wù)的線程;3. TIDYING:所有的任務(wù)都銷(xiāo)毀了,workCount 為 0。線程池的狀態(tài)在轉(zhuǎn)換為 TIDYING 狀態(tài)時(shí),會(huì)執(zhí) ?鉤??法 terminated();
4. TERMINATED:terminated() ?法結(jié)束后,線程池的狀態(tài)就會(huì)變成這個(gè)。
到此這篇關(guān)于詳解Java線程池的使用(7種創(chuàng)建方法)的文章就介紹到這了,更多相關(guān)Java線程池的使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring5新特性之Reactive響應(yīng)式編程
這篇文章主要介紹了Spring5新特性之Reactive響應(yīng)式編程,響應(yīng)式編程是一種編程范式,通用和專注于數(shù)據(jù)流和變化的,并且是異步的,下文更多詳細(xì)內(nèi)容,需要的小伙伴可以參考一下,希望對(duì)你有所幫助2022-03-03關(guān)于spring?aop兩種代理混用的問(wèn)題
這篇文章主要介紹了關(guān)于spring?aop兩種代理混用的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11Spring Boot集成spring-boot-devtools開(kāi)發(fā)時(shí)實(shí)現(xiàn)熱部署的方式
這篇文章主要介紹了Spring Boot集成spring-boot-devtools開(kāi)發(fā)時(shí)實(shí)現(xiàn)熱部署的方式,文中還給大家提到了spring boot 實(shí)現(xiàn)熱部署的方式及集成注意事項(xiàng),感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧2018-05-05詳解spring cloud構(gòu)建微服務(wù)架構(gòu)的網(wǎng)關(guān)(API GateWay)
這篇文章主要介紹了詳解spring cloud構(gòu)建微服務(wù)架構(gòu)的網(wǎng)關(guān)(API GateWay),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01java實(shí)現(xiàn)簡(jiǎn)單的學(xué)生管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單的學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02