Java 如何創(chuàng)建和使用ExecutorService
一、什么是ExecutorService?
ExecutorService 是 Java 中用來(lái)管理和執(zhí)行多線程任務(wù)的一種高級(jí)工具??梢杂行У毓芾砭€程的生命周期和任務(wù)的執(zhí)行過(guò)程,特別是在需要處理大量并發(fā)任務(wù)時(shí)尤為有用。
生動(dòng)形象的比喻,ExecutorService 就像是一個(gè)管理者,你可以把任務(wù)交給它,它會(huì)根據(jù)需要?jiǎng)?chuàng)建線程,并且確保任務(wù)按照你的要求執(zhí)行。
在實(shí)際編程中,可以通過(guò) ExecutorService 來(lái)避免直接操作線程,這樣做通常更安全和更高效。
可以創(chuàng)建一個(gè) ExecutorService 并告訴它需要執(zhí)行的任務(wù),ExecutorService 會(huì)根據(jù)需要?jiǎng)?chuàng)建線程,并在執(zhí)行完任務(wù)后將線程回收以便重用,這樣可以節(jié)省資源并提高性能。
看一個(gè)簡(jiǎn)單的例子:
假設(shè)有一個(gè)需要處理大量數(shù)據(jù)的任務(wù),可以創(chuàng)建一個(gè) ExecutorService,并告訴它希望同時(shí)執(zhí)行多少個(gè)任務(wù)。ExecutorService 會(huì)根據(jù)設(shè)定的自動(dòng)創(chuàng)建和管理線程,確保這些任務(wù)可以并發(fā)執(zhí)行而不會(huì)互相干擾。這種方式比手動(dòng)管理線程更容易,并且可以更好地利用計(jì)算機(jī)的多核處理能力。
// 創(chuàng)建一個(gè)固定大小的線程池,最多同時(shí)執(zhí)行兩個(gè)任務(wù)
ExecutorService executor = Executors.newFixedThreadPool(2);
// 提交兩個(gè)任務(wù)給線程池執(zhí)行
executor.submit(() -> {
System.out.println("任務(wù)1 正在執(zhí)行...");
// 這里放置任務(wù)1的具體代碼邏輯
});
executor.submit(() -> {
System.out.println("任務(wù)2 正在執(zhí)行...");
// 這里放置任務(wù)2的具體代碼邏輯
});
// 關(guān)閉線程池
executor.shutdown();二、ExecutorService的核心功能
創(chuàng)建固定大小的線程池
// 創(chuàng)建一個(gè)包含5個(gè)線程的固定大小線程池 ExecutorService executor = Executors.newFixedThreadPool(5);
使用場(chǎng)景: 當(dāng)需要限制同時(shí)執(zhí)行的線程數(shù)量時(shí),可以使用固定大小的線程池。這樣可以控制并發(fā)線程數(shù)量,避免系統(tǒng)資源被過(guò)度消耗。
創(chuàng)建可緩存的線程池
// 創(chuàng)建一個(gè)可根據(jù)需要自動(dòng)擴(kuò)展的線程池 ExecutorService executor = Executors.newCachedThreadPool();
使用場(chǎng)景: 當(dāng)有大量短期異步任務(wù)需要處理時(shí),可以使用可緩存線程池。它會(huì)根據(jù)任務(wù)的增加自動(dòng)創(chuàng)建新線程,并在空閑時(shí)重用現(xiàn)有線程,從而提高性能。
提交 Runnable 任務(wù)
executor.submit(() -> {
System.out.println("執(zhí)行任務(wù)1");
// 這里放置任務(wù)1的具體代碼邏輯
});使用場(chǎng)景: 當(dāng)需要執(zhí)行沒(méi)有返回值的簡(jiǎn)單任務(wù)時(shí),可以提交實(shí)現(xiàn)了 Runnable 接口的任務(wù)。例如,清理臨時(shí)文件、發(fā)送通知等異步操作。
提交 Callable 任務(wù)并獲取結(jié)果
Future<Integer> future = executor.submit(() -> {
System.out.println("執(zhí)行任務(wù)2");
// 這里放置任務(wù)2的具體代碼邏輯
// 返回任務(wù)執(zhí)行結(jié)果
return fu;
});
try {
// 獲取任務(wù)執(zhí)行結(jié)果,可能會(huì)阻塞直到任務(wù)完成
Integer result = future.get();
System.out.println("任務(wù)2 的結(jié)果是:" + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}使用場(chǎng)景: 當(dāng)需要執(zhí)行有返回值的任務(wù),并且可能需要等待任務(wù)完成后獲取結(jié)果時(shí),可以提交實(shí)現(xiàn)了 Callable 接口的任務(wù),并使用 Future 對(duì)象獲取任務(wù)的返回值。
擴(kuò)展:
Future 接口提供了一個(gè)特殊的阻塞方法 get(),它返回 Callable 任務(wù)執(zhí)行的實(shí)際結(jié)果,但如果是 Runnable 任務(wù),則只會(huì)返回 null。
如果調(diào)用get()方法時(shí)任務(wù)仍在運(yùn)行,那么調(diào)用將會(huì)一直被執(zhí)阻塞,直到任務(wù)正確執(zhí)行完畢并且結(jié)果可用時(shí)才返回。
get() 方法是阻塞的,而且并不知道要阻塞多長(zhǎng)時(shí)間。因此可能導(dǎo)致應(yīng)用程序的性能降低。如果結(jié)果數(shù)據(jù)并不重要,那么我們可以使用超時(shí)機(jī)制來(lái)避免長(zhǎng)時(shí)間阻塞。
// 等待 200 毫秒 String result = future.get(200, TimeUnit.MILLISECONDS);
這個(gè)get() 的重載,第一個(gè)參數(shù)為超時(shí)的時(shí)間,第二個(gè)參數(shù)為時(shí)間的單位。
控制線程池的關(guān)閉
// 平穩(wěn)關(guān)閉線程池,等待所有任務(wù)執(zhí)行完成 executor.shutdown();
使用場(chǎng)景: 當(dāng)不再需要使用 ExecutorService 時(shí),應(yīng)該調(diào)用 shutdown() 方法來(lái)關(guān)閉線程池。確保已提交的任務(wù)能夠完成執(zhí)行,避免資源泄漏和任務(wù)丟失的問(wèn)題。
三、如何創(chuàng)建和使用ExecutorService?
使用 Executors 工廠類來(lái)創(chuàng)建不同類型的 ExecutorService。
newFixedThreadPool(int n) 可以創(chuàng)建一個(gè)固定大小的線程池。
newCachedThreadPool() 則可以創(chuàng)建一個(gè)根據(jù)需要自動(dòng)擴(kuò)展的線程池。
實(shí)際案例:
創(chuàng)建一個(gè)簡(jiǎn)單的多線程程序,使用 ExecutorService 執(zhí)行一批任務(wù),并獲取它們的執(zhí)行結(jié)果。
public static void main(String[] args) {
// 創(chuàng)建一個(gè)固定大小為3的線程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 創(chuàng)建一個(gè)列表來(lái)保存提交的任務(wù)
List<Future<Integer>> futures = new ArrayList<>();
// 提交10個(gè)任務(wù),每個(gè)任務(wù)返回任務(wù)ID乘以2的結(jié)果
for (int i = 1; i <= 10; i++) {
final int taskId = i;
// 提交 Callable 任務(wù),并將 Future 對(duì)象保存到列表中
Future<Integer> future = executor.submit(() -> {
System.out.println("任務(wù) " + taskId + " 開(kāi)始執(zhí)行");
// 模擬任務(wù)執(zhí)行耗時(shí)
Thread.sleep(2000);
// 返回任務(wù)的結(jié)果
return taskId * 2;
});
// 將 Future 對(duì)象添加到列表中
futures.add(future);
}
// 等待所有任務(wù)完成,并打印各任務(wù)的執(zhí)行結(jié)果
for (Future<Integer> future : futures) {
try {
// 獲取任務(wù)執(zhí)行結(jié)果,可能會(huì)阻塞直到任務(wù)完成
Integer result = future.get();
System.out.println("任務(wù)結(jié)果: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
// 關(guān)閉線程池
executor.shutdown();
}
// 輸出結(jié)果
任務(wù) 1 開(kāi)始執(zhí)行
任務(wù) 2 開(kāi)始執(zhí)行
任務(wù) 3 開(kāi)始執(zhí)行
任務(wù)結(jié)果: 2
任務(wù)結(jié)果: 4
任務(wù) 4 開(kāi)始執(zhí)行
任務(wù)結(jié)果: 6
任務(wù) 5 開(kāi)始執(zhí)行
任務(wù)結(jié)果: 8
任務(wù) 6 開(kāi)始執(zhí)行
任務(wù)結(jié)果: 10
任務(wù) 7 開(kāi)始執(zhí)行
任務(wù)結(jié)果: 12
任務(wù) 8 開(kāi)始執(zhí)行
任務(wù)結(jié)果: 14
任務(wù) 9 開(kāi)始執(zhí)行
任務(wù)結(jié)果: 16
任務(wù) 10 開(kāi)始執(zhí)行
任務(wù)結(jié)果: 18
任務(wù)結(jié)果: 20時(shí)間不能增添一個(gè)人的生命,然而珍惜光陰卻可使生命變得更有價(jià)值
到此這篇關(guān)于Java ExecutorService的文章就介紹到這了,更多相關(guān)Java ExecutorService內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java圖片驗(yàn)證碼實(shí)現(xiàn)示例分享
這篇文章主要介紹了java實(shí)現(xiàn)圖片驗(yàn)證碼示例,需要的朋友可以參考下2014-02-02
SpringBoot接口加密與解密的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot接口加密與解密的實(shí)現(xiàn)2023-10-10
實(shí)例解析使用Java實(shí)現(xiàn)基本的音頻播放器的編寫(xiě)要點(diǎn)
這篇文章主要介紹了使用Java實(shí)現(xiàn)基本的音頻播放器的代碼要點(diǎn)實(shí)例分享,包括音頻文件的循環(huán)播放等功能實(shí)現(xiàn)的關(guān)鍵點(diǎn),需要的朋友可以參考下2016-01-01
Java實(shí)現(xiàn)監(jiān)控多個(gè)線程狀態(tài)的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇Java實(shí)現(xiàn)監(jiān)控多個(gè)線程狀態(tài)的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03
Java實(shí)現(xiàn)Excel文件加密解密的示例代碼
設(shè)置excel文件保護(hù)時(shí),通常可選擇對(duì)整個(gè)工作簿進(jìn)行加密保護(hù)。無(wú)需設(shè)置文檔保護(hù)時(shí),可撤銷(xiāo)密碼保護(hù),即解密文檔。本文將通過(guò)java程序演示以上加密、解密方法的實(shí)現(xiàn),感興趣的可以了解一下2022-05-05
Java?synchornized與ReentrantLock處理并發(fā)出現(xiàn)的錯(cuò)誤
synchronized機(jī)制提供了對(duì)每個(gè)對(duì)象相關(guān)的隱式監(jiān)視器鎖,并強(qiáng)制所有鎖的獲取和釋放都必須在同一個(gè)塊結(jié)構(gòu)中。當(dāng)獲取了多個(gè)鎖時(shí),必須以相反的順序釋放。即synchronized對(duì)于鎖的釋放是隱式的2023-01-01
spring boot 1.5.4 集成shiro+cas,實(shí)現(xiàn)單點(diǎn)登錄和權(quán)限控制
這篇文章主要介紹了spring boot 1.5.4 集成shiro+cas,實(shí)現(xiàn)單點(diǎn)登錄和權(quán)限控制,需要的朋友可以參考下2017-06-06
spring使用WebSocket注入service層失敗問(wèn)題及解決
這篇文章主要介紹了spring使用WebSocket注入service層失敗問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
JAVA實(shí)現(xiàn)二維碼生成加背景圖代碼實(shí)例
這篇文章主要介紹了JAVA實(shí)現(xiàn)二維碼生成加背景圖代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
Mybatis參數(shù)(Parameters)傳遞方式
這篇文章主要介紹了Mybatis參數(shù)(Parameters)傳遞方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12

