public class AsyncDemo { private static void doSomeTask() { System.out.println("Hello World"); } private static void onCompletion() { System.out.println("All tasks finished"); } public static void main(String[] args) { ExecutorService executor = Executors.newCachedThreadPool(); final CountDownLatch latch = new CountDownLatch(2); executor.execute(new Task(latch)); executor.execute(new Task(latch)); executor.execute(() -> { try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } onCompletion(); }); executor.shutdown(); } private static class Task implements Runnable { /** * CountDownLatch 是JDK提供的一個簡單的線程監測工具 * 基於簡單的計數,調用countDown()方法代表當前線程已經終止 * 在監測線程中調用await()方法,該方法會一直掛起直到全部其它線程終止 */ private final CountDownLatch latch; public Task(CountDownLatch latch) { this.latch = latch; } @Override public void run() { try { doSomeTask(); } catch (Exception e) { e.printStackTrace(); } finally { latch.countDown(); } } } }
這裏有兩點須要補充:web
1.若是你是用main方法啓動的線程,這種調用方法是沒有問題的,JDK會確保全部線程都終止之後main方法才退出。可是若是main方法不是異步任務的啓動者(如JUnit,Spring,Tomcat),一旦啓動以後laucher將會失去對線程的控制。如在JUnit中laucher提交完任務後就會被認爲全部過程已完成,其它線程會被強行終止。tomcat
2.正由於如此,請根據環境使用正確的Executor。好比,在web環境中,應該選用tomcat(或Spring)管理的線程池做爲Executor,這樣才能確保web應用對於異步任務的整個生命週期具備控制權;若是你選用JDK的線程池有什麼後果呢?任務也許能夠正常執行,當一旦你終止web-app,正在執行的異步線程並不會被正常kill掉,並由此形成內存泄漏或其它不可預見的後果。app