java?for循環(huán)內(nèi)執(zhí)行多線程問(wèn)題
java用多線程來(lái)加快循環(huán)效率
線程池搭配閉鎖
涉及知識(shí):Executors(線程池)、CountDownLatch(閉鎖)
優(yōu)點(diǎn):代碼簡(jiǎn)潔,方便閱讀,性能穩(wěn)定;
缺點(diǎn):Executors創(chuàng)建的線程池是公用的,如果多個(gè)地方使用這種循環(huán)多線程的方式,就會(huì)搶奪線程池資源,這樣運(yùn)行速度也會(huì)降低;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class test{
/** 固定的線程池(當(dāng)前線程池大小為5) */
private static final ExecutorService executor = Executors.newFixedThreadPool(5);
public static void main(String[] args) throws Exception {
/**
* 兩個(gè)要點(diǎn):
* 1.用Executors實(shí)現(xiàn)固定大小的線程池,從而達(dá)到控制硬件資源消耗的目的。
* 2.用CountDownLatch(閉鎖),來(lái)確保循環(huán)內(nèi)的多線程都執(zhí)行完成后,再執(zhí)行后續(xù)代碼
*/
// 初始化數(shù)據(jù)
List<Map<String,Object>> list = new ArrayList<>();
for(int i=0;i<50;i++){
Map<String,Object> object = new HashMap<>();
object.put("index",i);
list.add(object);
}
// 初始化計(jì)時(shí)器
CountDownLatch cdl = new CountDownLatch(list.size());
System.out.println("====== 線程開始 =====");
// 遍歷
for(Map<String,Object> object:list){
// 開啟線程
executor.submit(new Runnable() {
@Override
public void run() {
try {
Thread t = Thread.currentThread();
String name = t.getName();
// 模擬運(yùn)行耗時(shí)
Thread.sleep(500);
System.out.println(name+":執(zhí)行到"+object.get("index"));
object.put("status","已經(jīng)執(zhí)行過(guò)");
} catch (InterruptedException e) {
e.printStackTrace();
}
// 閉鎖-1
cdl.countDown();
}
});
}
// 調(diào)用閉鎖的await()方法,該線程會(huì)被掛起,它會(huì)等待直到count值為0才繼續(xù)執(zhí)行
// 這樣我們就能確保上面多線程都執(zhí)行完了才走后續(xù)代碼
cdl.await();
//關(guān)閉線程池
executor.shutdown();
System.out.println("====== 線程結(jié)束 =====");
// 校驗(yàn)多線程正確性
for(Map<String,Object> object:list){
System.out.println(object.get("index") + ":" + object.get("status"));
}
}
}for循環(huán)中使用多線程
每個(gè)service負(fù)責(zé)一個(gè)業(yè)務(wù),多次進(jìn)行重復(fù)業(yè)務(wù)就要使用到for循環(huán),例如對(duì)某個(gè)存儲(chǔ)id的集合遍歷,并為每個(gè)id創(chuàng)建一些東西。
但是使用單線程執(zhí)行任務(wù)會(huì)因?yàn)榈却洗稳蝿?wù)執(zhí)行完而浪費(fèi)很多時(shí)間,并且一旦某次執(zhí)行報(bào)錯(cuò),任務(wù)就會(huì)停止執(zhí)行,明顯不符合我們的要求。
這種情況就在for循環(huán)中使用多線程。
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
public class Test {
/**
* ThreadPool 自定義一個(gè)線程池
*/
private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(60000));
public static void main(String[] args) {
//自己的數(shù)組或集合,這里不再進(jìn)行填充
String[] ids = new String[10]
for (String id : ids) {
EXECUTOR.execute(new Runnable() {
@Override
public void run() {
try {
//需要執(zhí)行的業(yè)務(wù)邏輯
System.out.println("業(yè)務(wù)邏輯正在執(zhí)行");
} catch (Exception e) {
//todo
}
}
});
}
}
}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
spring boot整合Shiro實(shí)現(xiàn)單點(diǎn)登錄的示例代碼
本篇文章主要介紹了spring boot整合Shiro實(shí)現(xiàn)單點(diǎn)登錄的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
Swagger2匹配多個(gè)controller代碼實(shí)例
這篇文章主要介紹了Swagger2匹配多個(gè)controller代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
舉例講解Java設(shè)計(jì)模式編程中Decorator裝飾者模式的運(yùn)用
這篇文章主要介紹了Java設(shè)計(jì)模式編程中Decorator裝飾者模式的運(yùn)用,裝飾者模式就是給一個(gè)對(duì)象動(dòng)態(tài)的添加新的功能,裝飾者和被裝飾者實(shí)現(xiàn)同一個(gè)接口,裝飾者持有被裝飾者的實(shí)例,需要的朋友可以參考下2016-05-05
Java Iterator迭代器_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
迭代器是一種模式,它可以使得對(duì)于序列類型的數(shù)據(jù)結(jié)構(gòu)的遍歷行為與被遍歷的對(duì)象分離,接下來(lái)通過(guò)本文給大家分享Java Iterator迭代器_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理,需要的朋友參考下吧2017-05-05
修改Springboot默認(rèn)序列化工具Jackson配置的實(shí)例代碼
這篇文章主要介紹了如何修改Springboot默認(rèn)序列化工具Jackson的配置,當(dāng)Spring容器中存在多個(gè)同類型的Bean時(shí),默認(rèn)情況下最后一個(gè)創(chuàng)建的Bean將作為首選Bean,文中通過(guò)代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-02-02
Java 8 Stream 的終極技巧——Collectors 功能與操作方法詳解
這篇文章主要介紹了Java 8 Stream Collectors 功能與操作方法,結(jié)合實(shí)例形式詳細(xì)分析了Java 8 Stream Collectors 功能、操作方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下2020-05-05
Struts 2 實(shí)現(xiàn)Action的幾種方式
本篇文章主要介紹了Struts 2 實(shí)現(xiàn)Action的幾種方式,Struts 2框架下實(shí)現(xiàn)Action類有三種方式,有興趣的可以了解一下2017-10-10

