java中線程池最實(shí)用的創(chuàng)建與關(guān)閉指南
前言
在日常的開發(fā)工作當(dāng)中,線程池往往承載著一個(gè)應(yīng)用中最重要的業(yè)務(wù)邏輯,因此我們有必要更多地去關(guān)注線程池的執(zhí)行情況,包括異常的處理和分析等。
線程池創(chuàng)建
避免使用Executors創(chuàng)建線程池,主要是避免使用其中的默認(rèn)實(shí)現(xiàn),那么我們可以自己直接調(diào)用ThreadPoolExecutor的構(gòu)造函數(shù)來自己創(chuàng)建線程池。在創(chuàng)建的同時(shí),給BlockQueue指定容量就可以了。
private static ExecutorService executor = new ThreadPoolExecutor(10, 10, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue(10));
這種情況下,一旦提交的線程數(shù)超過當(dāng)前可用線程數(shù)時(shí),就會(huì)拋出java.util.concurrent.RejectedExecutionException,這是因?yàn)楫?dāng)前線程池使用的隊(duì)列是有邊界隊(duì)列,隊(duì)列已經(jīng)滿了便無法繼續(xù)處理新的請(qǐng)求。但是異常(Exception)總比發(fā)生錯(cuò)誤(Error)要好。
除了自己定義ThreadPoolExecutor外。還有其他方法。這個(gè)時(shí)候第一時(shí)間就應(yīng)該想到開源類庫,如apache和guava等。
推薦使用guava提供的ThreadFactoryBuilder來創(chuàng)建線程池。
public class ExecutorsDemo { private static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder() .setNameFormat("demo-pool-%d").build(); private static ExecutorService pool = new ThreadPoolExecutor(5, 200, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); public static void main(String[] args) { for (int i = 0; i < Integer.MAX_VALUE; i++) { pool.execute(new SubThread()); } } }
只需要執(zhí)行shutdown就可以優(yōu)雅關(guān)閉
package com.zxd.concurrent; import com.google.common.collect.Lists; import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class ThreadPool { public static void main(String[] args) { // TODO 如何正確優(yōu)雅簡單的關(guān)閉線程池 ,無須其他多余操 ;創(chuàng)建線程池我選擇用這種方法比較可靠 ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); //接收處理數(shù)據(jù)的結(jié)果集合 List<Integer> resList = Lists.newArrayList(); //開啟的任務(wù) 我們?cè)O(shè)置的核心處理線程數(shù)5個(gè)所以 會(huì)有多出來的線程在隊(duì)列中等待 for (int i = 0; i < 30; i++) { executor.execute(new Task(i, resList)); } //1、關(guān)閉線程池 一定要在循環(huán)結(jié)束關(guān)閉 //2、這個(gè)關(guān)閉方法不會(huì)立即關(guān)閉所有在執(zhí)行的任務(wù)線程, executor.shutdown(); //4.這里是檢查線程池是否所有任務(wù)都執(zhí)行完畢關(guān)閉 int j = 0; while (true) { //5.這里是等線程池徹底關(guān)閉以后做的判斷 保證所有線程池已經(jīng)全部關(guān)閉退出while循環(huán) if (executor.isTerminated()) { System.out.println("所有線程已經(jīng)運(yùn)行完畢:" + j); break; } // 為避免一直循環(huán) 加個(gè)睡眠 try { //如果執(zhí)行shutdown方法沒有關(guān)閉的線程池線程池會(huì)嘗試關(guān)閉 System.out.println("嘗試關(guān)閉線程次數(shù):" + j); j++; Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } //FIXME 3、下面的方法會(huì)立即關(guān)閉線程池,沒有執(zhí)行完的也不會(huì)在執(zhí)行了,如果有等待隊(duì)列的任務(wù)也不會(huì)繼續(xù)執(zhí)行 System.out.println("【完成的總線程數(shù)】:" + resList.size()); } static class Task implements Runnable { int name; List<Integer> list; public Task(int name, List<Integer> list) { this.name = name; this.list = list; } @Override public void run() { for (int i = 1; i <= 10; i++) { int j = i * 10; // 做業(yè)務(wù)處理 //System.out.println("task " + name + " is running"); } list.add(name + 1); System.out.println("task " + name + " is over"); } } }
輸出結(jié)果
task 0 is over
task 3 is over
task 1 is over
task 2 is over
task 7 is over
task 6 is over
task 5 is over
嘗試關(guān)閉線程次數(shù):0
task 10 is over
task 9 is over
task 4 is over
task 8 is over
task 14 is over
task 13 is over
task 12 is over
task 11 is over
task 18 is over
task 17 is over
task 16 is over
task 15 is over
task 22 is over
task 21 is over
task 20 is over
task 19 is over
task 26 is over
task 25 is over
task 24 is over
task 23 is over
task 29 is over
task 28 is over
task 27 is over
所有線程已經(jīng)運(yùn)行完畢:1
【完成的總線程數(shù)】:30
執(zhí)行shutdownNow關(guān)閉的測試
package com.zxd.concurrent; import com.google.common.collect.Lists; import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class ThreadPool { public static void main(String[] args) { // TODO 如何正確優(yōu)雅簡單的關(guān)閉線程池 ,無須其他多余操 ;創(chuàng)建線程池我選擇用這種方法比較可靠 ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); //接收處理數(shù)據(jù)的結(jié)果集合 List<Integer> resList = Lists.newArrayList(); //開啟的任務(wù) 我們?cè)O(shè)置的核心處理線程數(shù)5個(gè)所以 會(huì)有多出來的線程在隊(duì)列中等待 for (int i = 0; i < 200; i++) { executor.execute(new Task(i, resList)); } //1、關(guān)閉線程池 一定要在循環(huán)結(jié)束關(guān)閉 //2、這個(gè)關(guān)閉方法不會(huì)立即關(guān)閉所有在執(zhí)行的任務(wù)線程, // executor.shutdown(); //FIXME 3、下面的方法會(huì)立即關(guān)閉線程池,沒有執(zhí)行完的也不會(huì)在執(zhí)行了,如果有等待隊(duì)列的任務(wù)也不會(huì)繼續(xù)執(zhí)行 List<Runnable> list = executor.shutdownNow(); System.out.println("c剩余的沒有執(zhí)行的任務(wù)【線程數(shù)】= " + list.size()); System.out.println("【完成的總線程數(shù)】:" + resList.size()); //4.這里是檢查線程池是否所有任務(wù)都執(zhí)行完畢關(guān)閉 int j = 0; while (true) { //5.這里是等線程池徹底關(guān)閉以后做的判斷 保證所有線程池已經(jīng)全部關(guān)閉退出while循環(huán) if (executor.isTerminated()) { System.out.println("所有線程已經(jīng)運(yùn)行完畢:" + j); break; } // 為避免一直循環(huán) 加個(gè)睡眠 try { //如果執(zhí)行shutdown方法沒有關(guān)閉的線程池線程池會(huì)嘗試關(guān)閉 System.out.println("嘗試關(guān)閉線程次數(shù):" + j); j++; Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } } static class Task implements Runnable { int name; List<Integer> list; public Task(int name, List<Integer> list) { this.name = name; this.list = list; } @Override public void run() { for (int i = 1; i <= 10; i++) { int j = i * 10; // 做業(yè)務(wù)處理 //System.out.println("task " + name + " is running"); } list.add(name + 1); System.out.println("task " + name + " is over"); } } }
輸出結(jié)果
總結(jié)
到此這篇關(guān)于java中線程池最實(shí)用的創(chuàng)建與關(guān)閉的文章就介紹到這了,更多相關(guān)java線程池創(chuàng)建與關(guān)閉內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解如何將已有項(xiàng)目改造為Spring Boot項(xiàng)目
本篇文章主要介紹了如何將已有項(xiàng)目改造為Spring Boot項(xiàng)目,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11maven項(xiàng)目install時(shí)忽略執(zhí)行test方法的總結(jié)
這篇文章主要介紹了maven項(xiàng)目install時(shí)忽略執(zhí)行test方法的總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03Java實(shí)現(xiàn)支付寶之第三方支付寶即時(shí)到賬支付功能
這篇文章主要介紹了Java實(shí)現(xiàn)支付寶之第三方支付寶即時(shí)到賬支付功能的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07IDEA配置MAVEN本地倉庫的實(shí)現(xiàn)步驟
本文主要介紹了IDEA配置MAVEN本地倉庫的實(shí)現(xiàn)步驟,將詳細(xì)介紹如何配置Maven環(huán)境變量,Maven配置文件,可以輕松地設(shè)置和配置MAVEN本地倉庫,以便在IDEA中享受更高效的開發(fā)體驗(yàn)2023-08-08java啟動(dòng)時(shí)自定義配置文件路徑,自定義log4j2.xml位置方式
這篇文章主要介紹了java啟動(dòng)時(shí)自定義配置文件路徑,自定義log4j2.xml位置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08關(guān)于@ComponentScan注解的用法及作用說明
這篇文章主要介紹了關(guān)于@ComponentScan注解的用法及作用說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09SpringBoot項(xiàng)目實(shí)現(xiàn)分布式日志鏈路追蹤
這篇文章主要給大家介紹了Spring Boot項(xiàng)目如何實(shí)現(xiàn)分布式日志鏈路追蹤,文中通過代碼示例給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07