天天看點

線程等待的四種方式-join/future/countDownLatch/cylicBarrier實作

場景如下:一共三個線程a,b,c,其中c需要用到a,b,執行的結果,應該怎麼處理?    

1)CountDownLatch,主線程中調用await方法,每個線程調用countdown

上面兩種方法需要分别調用多次join或future的get方法,不太好,有一種方法是使用CountDownLatch類

認知CountDownLatch的方法:

await():阻塞主線程,直到countDownLatch的計數器減少到0的位置,

countDown:将目前的計數器減1

getCount:傳回目前的數

思路如下:讓a,b線程使用CountDowmLatch,然後執行countDownLatch的await方法

主類:

    public static void main(String[] args) {

        CountDownLatch countDownLaunch = new CountDownLatch(5);

        for(int i=1;i<6;i++){

            ThreadWithCountDownLatch threadWithCountDownLatch = new ThreadWithCountDownLatch(i*1000L,countDownLaunch,"THREAD"+i);

            Thread thread = new Thread(threadWithCountDownLatch);

            thread.start();

        }

        mainThreadWork();

        try {

            countDownLaunch.await();//下面的代碼要等待所有的countDown的計數器為零再執行

        } catch (InterruptedException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        System.out.println("all done");    

    }

線程類:

public class ThreadWithCountDownLatch implements Runnable{

    long time;

    CountDownLatch countDownLatch;

    String name;

    public ThreadWithCountDownLatch(long time,CountDownLatch countDownLatch,String name){

        this.time=time;

        this.countDownLatch = countDownLatch;

        this.name=name;

    }

    @Override

    public void run() {

        try {

            System.out.println(name+" start");

            work(time);

            System.out.println(name+" end");

        } catch (InterruptedException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }finally{

            countDownLatch.countDown();

        }

    }

    private void work(long time2) throws InterruptedException {

        Thread.sleep(time2);    

    }

}

2)CyclicBarrier-每個線程中調用await,調用達到次數再一起放行

調用栅欄(計數器為5)的await,相當于告訴栅欄已經有一個線程到達栅欄,同時線程本身不再繼續執行;當cyclicBarrier的await方法調用5次時,所有線程繼續執行,同時觸發栅欄的run方法

主類:

    public static void main(String[] args) {

        CyclicBarrier cylicBarrier = new CyclicBarrier(5,new Runnable() {

            //栅欄動作,在計數器為零的時候執行

            @Override

            public void run() {//栅欄的await方法執行五次後會調用此處

                // TODO Auto-generated method stub

                System.out.println("all work done");

            }

        });

        ExecutorService pool = Executors.newFixedThreadPool(5);

        for(int i=1;i<6;i++){

            pool.submit(new ThreadWithCyclicBarrier(i,cylicBarrier));

        }

        pool.shutdown();

        System.out.println("last ");    

    }

線程類:

public class ThreadWithCyclicBarrier  implements Runnable{

    int id;

    CyclicBarrier cyclicBarrier;

    public ThreadWithCyclicBarrier(int id,CyclicBarrier cyclicBarrier){

        this.id = id;

        this.cyclicBarrier=cyclicBarrier;

    }

    @Override

    public void run() {

        System.out.println("thread"+id+" start");

        try {

            cyclicBarrier.await();//栅欄計數值為零後會繼續執行

            Thread.sleep(1000L);

        } catch (InterruptedException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        } catch (BrokenBarrierException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        System.out.println("thread"+id+" end");

    }

}

3)join方法實作

對a,b使用a.join()和b.join();    然後下面使用c.start()

SubTThread subthread = new SubTThread("subthread");

        SubTThread subthread2 = new SubTThread("subthread2");

        SubTThread subthread3 = new SubTThread("subthread3");

        Thread thread = new Thread(subthread);

        Thread thread2 = new Thread(subthread2);

        Thread thread3 = new Thread(subthread3);

        thread.start();

        thread2.start();

        mainThreadWork();

        System.out.println("wait subthread done");

        try {

            thread.join();

            thread2.join();//當thread和thread2的run方法執行完畢後才會繼續下面的代碼

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        thread3.start();

        System.out.println("all work done");

4)線程池submit線程傳回Future,并調用future的get方法

使用線程池,線程池submit線程傳回Future,并調用future的get方法.則get方法下的代碼都需要等待調用了get方法的線程完全執行後再執行

    public static void main(String[] args) {

        ExecutorService pool = Executors.newFixedThreadPool(3);

        SubTThreadByRun subthread = new SubTThreadByRun("subthread");

        SubTThreadByRun subthread2 = new SubTThreadByRun("subthread2");        

        Thread thread = new Thread(subthread);

        Thread thread2 = new Thread(subthread2);

        ThreadByCall threadByCall = new ThreadByCall("call1");

        Future future1 = pool.submit(thread);

        Future future2 = pool.submit(thread2);

        Future future3 = pool.submit(threadByCall);

        mainThreadWork();

        try {

            future1.get();

            future2.get();

            String str = (String) future3.get();//下面的代碼需要等待thread1/thread2和threadByCall 執行完畢後執行下面的代碼

            System.out.println("得到結果:"+str);

        } catch (InterruptedException e) {

            e.printStackTrace();

        } catch (ExecutionException e) {

            e.printStackTrace();

        }

SubTThreadByRun subthread3 = new SubTThreadByRun("subthread3");        

Thread thread3 = new Thread(subthread3);

        thread3.start();

        System.out.println("all work done");

        pool.shutdown();//關閉線程池

    }

四種實作方式比較

join--适用于少量線程

線程池submit+future.get--适用于實際使用的線程數量不定,且所有線程執行完畢

CountDownLatch--設定線程數,每個線程結尾使用countDown()方法減值,主線程中調用await方法來阻塞,當資料減為0時,主線程繼續執行,适用于實際使用線程數量固定

栅欄--多個線程都執行到某個點暫停,然後再一起開始,并且增加栅欄的run方法

new CyclicBarrier(5,new Runnable());每個線程執行到CyclicBarrier.await方法,線程會暫停,當await方法執行5次時,所有線程繼續運作,并且執行cyclicBarrier的runner的run方法