Java藉助CountDownLatch完成異步回調

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

相關文章
相關標籤/搜索