使用執行緒池與CountDownLatch多執行緒提升系統性能
阿新 • • 發佈:2019-01-06
下面這個業務場景,大家可能都會遇到,在遍歷一個list的時候,需要對list中的每個物件,做一些複雜又耗時的操作,比如取出物件的uid,遠端呼叫一次userservice的getUserByUid方法,這屬於IO操作了,可怕的是遍歷到每個物件時,都得執行一次這種RPC的IO操作(甚至不止一次,因為可能還有別的介面需要去調)還有複雜的業務邏輯需要cpu去計算。
以上這種場景,屬於IO操作和CPU操作混合,如果是純IO操作的話,也是可以用這種方案來解決的,因為一個執行緒向遠端伺服器發出請求了,再等待響應的過程中,其他執行緒也可以向遠端伺服器發出請求(請求-請求-響應-響應),這樣也比請求-響應-請求-響應 這種模式要快。
下面貼上一個小demo,供大家參考。
ExecutorService作為一個執行緒池,然後利用CountDownLatch可以讓指定數量的執行緒都執行完再執行主執行緒的特性。就可以實現多執行緒提速了。
套路是這樣的:
1、實現runnable介面實現一個run方法,裡面執行我們的耗時複雜業務操作。
2、在迴圈裡給list裡的每個物件分配一個執行緒
3、使用CountDownLatch讓主執行緒等待工作執行緒全部執行完畢後之後,再繼續執行。
//多核定製執行緒池
這裡寫程式碼片
static ExecutorService taskPool = ExecutorUtils.newMultiCpuFlexibleThreadPool(5, “task-pool”);
//為了提高效能,耗時的業務邏輯操作做使用多執行緒處理 public class RunnerTask implements Runnable { private EnumSet<GoodsMsgEnum.property> goodProperty; private List<GoodAllMsg> resultList; private UserApply item; private String logStr; private CountDownLatch latch; public RunnerTask(List<GoodAllMsg> resultList,UserApply item,EnumSet<GoodsMsgEnum.property> goodProperty,String logStr,CountDownLatch latch) { this.resultList=resultList; this.item=item; this.goodProperty=goodProperty; this.logStr=logStr; this.latch=latch; } @Override public void run() { try { GoodAllMsg aa = goodsById(item.getInfoId(), goodProperty, logStr); if(aa!=null){ aa.setAuditType(GlobalsDataCache.sysStatus.get(GlobalsVar.GOOD_AUDIT_STATUS_ACTIVE_PREFIX+item.getStatus())); addTotalList(resultList,aa); } } catch (Exception e) { e.printStackTrace(); }finally { if(this.latch!=null){ latch.countDown(); } } } } private synchronized void addTotalList(List<GoodAllMsg> resultList,GoodAllMsg item){ resultList.add(item); } /** * 多執行緒處理業務邏輯,提升效能 * @param taskList 任務佇列 * @param resultList 結果集 * @param goodProperty * @param logStr */ public List<GoodAllMsg> multiThreadProcess(List<UserApply> taskList,List<GoodAllMsg> resultList,EnumSet<GoodsMsgEnum.property> goodProperty,String logStr) throws InterruptedException { if(taskList!=null && !taskList.isEmpty()){ //建立閉鎖,計數器大小為任務多列的長多 CountDownLatch latch=new CountDownLatch(taskList.size()); for(UserApply item:taskList){ //把閉鎖物件傳入執行緒中,並在執行緒的finally代買塊中將閉鎖計數器減一 RunnerTask runnerTask=new RunnerTask(resultList,item,goodProperty,logStr,latch); taskPool.execute(runnerTask); } //主執行緒開始等待,直到計數器大小為0,返回結果 latch.await(); return resultList; } return new ArrayList<GoodAllMsg>(); }