多線程在學(xué)校的時(shí)候其實(shí)用的非常少蚣常,甚至幾乎用不到市咽,但是在公司是不一樣的,用的非常多抵蚊,畢竟用戶數(shù)據(jù)量十分的大施绎,曾經(jīng)實(shí)習(xí)我在一個(gè)項(xiàng)目里面做過一個(gè)數(shù)據(jù)處理,是計(jì)算這人和人之間的關(guān)系度贞绳,從而推出哪幾個(gè)人的親密度達(dá)到要求谷醉,如果不用多線程,要把這一批數(shù)據(jù)計(jì)算完冈闭,那么是需要大概一年時(shí)間俱尼,后來把時(shí)間縮短到了8天,降低了兩個(gè)數(shù)量級(jí)萎攒。
1遇八、我一般是這樣用線程池的,首先建立一個(gè)池子躺酒,當(dāng)然有時(shí)候有現(xiàn)成的池子給你用押蚤,看業(yè)務(wù)是自己創(chuàng)建還是用公共的。
private static final ExecutorService? commentExecutor =new ThreadPoolExecutor(20, 20, 1L,?
TimeUnit.MINUTES, new ArrayBlockingQueue<>(30),? r ->new Thread(r,"comment"));? //新建立一個(gè)池子羹应,看業(yè)務(wù)哈揽碘,一般這樣是可以的,各個(gè)參數(shù)這里不展開說园匹,后面會(huì)解釋的雳刺,看業(yè)務(wù)設(shè)計(jì)參數(shù)值;
2裸违、然后往池子里面提任務(wù)
List<T>?commentInfos = Lists.newCopyOnWriteArrayList(); //一般情況下ArrayList就可以了掖桦,這是用guava的
commentExecutor.submit(() -> {
try {
commentInfos.add(buildComment(reqParam));
}catch (Exception e) {
logger.info("buildComment error", e);
}
})
buildComment(reqParam) 這個(gè)是執(zhí)行任務(wù)的函數(shù),計(jì)算完后結(jié)果放到了commentInfos 集合中供汛;
如果是批量計(jì)算型任務(wù)枪汪,而且事先能知道批量數(shù),可以結(jié)合CountDownLatch使用怔昨,目的可以通過它來控制所有線程計(jì)算完后再往下走雀久;
也是比較常用的;
3趁舀、CountDownLatch 結(jié)合使用
try {
final CountDownLatch latch =new CountDownLatch(reqParam.getProductNos().size()); //事先獲取到批次
reqParam.getProductNos().forEach(p ->? //遍歷
commentExecutor.submit(() -> {? //每一個(gè)批次提交到池子里面
try {
commentInfos.add(buildComment(p,reqParam));? //開始運(yùn)算赖捌,運(yùn)算的結(jié)果放到commentInfos
}catch (Exception e) {
logger.info("buildComment error", e);
}finally {
latch.countDown(); //每個(gè)線程完成就釋放掉一個(gè)latch
}
})
);
latch.await(); //等待所有的latch釋放掉,也就是每一個(gè)線程都執(zhí)行完成
}catch (Exception e) {
logger.error("異常", e);
return WebResponse.fail(e.getMessage());
}finally {
logger.info("結(jié)果 commentInfos:{},計(jì)算耗時(shí):{}", JsonUtil.encode(commentInfos), stopwatch.elapsed(TimeUnit.MILLISECONDS));
}
可能沒用過線程池的小伙伴第一次看有點(diǎn)不明白矮烹,沒關(guān)系越庇,等以后工作中用到再翻翻就好了罩锐。