多執行緒優化執行效率
阿新 • • 發佈:2018-12-11
在專案開發中,碰到了一些耗時任務的問題.
需要使用多執行緒,本文在使用原生JDK7的情況下優化
純非同步方式可以使用Java8或者引入RxJava框架進行程式設計。
普通任務
同步任務流程圖如下
假定場景如下:
- taskA 耗時1秒
- taskB 耗時2秒
- taskC 耗時3秒
通常的操作就是遍歷任務
+執行任務
, 程式碼如下
// 任務A Runnable taskA = ()->{ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }; // 任務B Runnable taskB = ()->{ try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } }; // 任務C Runnable taskC = ()->{ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } }; // 任務組 Runnable [] taskArray = new Runnable[]{taskA,taskB,taskC}; /** * 執行所有人物 */ @Test public void testSimple(){ Date start = new Date(); for (Runnable aTaskArray : taskArray) { aTaskArray.run(); } Date end = new Date(); System.out.println(end.getTime()-start.getTime()); }
完成任務耗時6
秒
多執行緒同步任務
為了提高執行效率,引入多執行緒,讓等待的時間不再累計,而是合併。
最終執行的時間是耗時最長的任務
執行時間
如下圖所示,多個任務同時執行
程式碼
為了簡便起見,使用了上面的任務組taskArray
物件。
在實際使用中可以自己實現Runnable介面並傳入CountDownLatch物件進行操作
/** * 同步等待所有任務處理完成方案 */ @Test public void testSync() throws InterruptedException { final CountDownLatch countDownLatch = new CountDownLatch(taskArray.length); ExecutorService executorService = Executors.newFixedThreadPool(5); Date start = new Date(); for (Runnable aTaskArray : taskArray) { executorService.execute(new Runnable() { @Override public void run() { aTaskArray.run(); countDownLatch.countDown(); } }); } countDownLatch.await(); Date end = new Date(); System.out.println(end.getTime()-start.getTime()); }
執行時間: 3
秒
使用 JDK5 提供的 CountDownLatch 進行同步優化
優點
- 不用修改後續的程式碼(因為是同步的,後續的內容依賴於本次的內容也不影響)
缺點
- 會造成呼叫執行緒等待
多執行緒非同步任務
/** * 非同步回撥方案 * @throws InterruptedException */ @Test public void testReturnAsync() throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(3); Date start = new Date(); AtomicInteger atomicInteger = new AtomicInteger(taskArray.length); for (Runnable aTaskArray : taskArray) { executorService.execute(new Runnable() { @Override public void run() { aTaskArray.run(); if(atomicInteger.decrementAndGet()==0){ Date end = new Date(); System.out.println(end.getTime()-start.getTime()); } } }); } System.out.println("等待子執行緒的結果"); Thread.sleep(5*1000); }
執行時間: 3
秒
優點
- 不會造成呼叫執行緒等待
缺點:
- 需要修改了法簽名,需要傳入Runnable物件,執行回撥,後續的程式碼需要跟著修改
總結
- 使用多執行緒非同步還是同步主要的決定因素在於:
呼叫執行緒是不是可以阻塞
- 多執行緒同步和多執行緒非同步的執行效率沒有差別