Java线程:CountDownLatch 与Thread 的 join()

需求:

  主程序中需要等待所有子线程完成后 再继续任务

两种实现方式:

  一种使用join() 方法:当在当前线程中调用某个线程 thread 的 join() 方法时,当前线程就会阻塞,直到thread 执行完成,当前线程才可以继续往下执行。join的工作原理是,不停检查thread是否存活,如果存活则让当前线程永远wait,直到thread线程终止,线程的this.notifyAll 就会被调用。

  还有一种使用CountDownLatch :创建一个计数器的 CountDownLatch ,让子线程持有这个CountDownLatch 实例,当子线程完成自己的工作后,调用countDownLatch.countDown() 方法将计数器减1。countDownLatch.await() 方法会一直阻塞直到计数器为0,主线程才会继续往下执行。

  以上两种方式在一下情境下可以区分差别:假设线程工作可以分为两个阶段,主线程只需要等待子线程完成他们各自工作的第一个阶段之后就可以开始自己的工作了,而不是必须等待子线程把他们的工作全部完成之后才能开始。在这种情况下,join是没办法实现这个场景的,而CountDownLatch却可以,因为它持有一个计数器,只要计数器为0,那么主线程就可以结束阻塞往下执行。我们可以在子线程完成第一阶段工作之后就把计数器减1即可,这样子线程在完成第一阶段工作之后,主线程就可以开始工作了。

没有使用这两种方式代码:

public class Test1 {
    static class HandleThread extends Thread {
        private String threadName;
        private List<String> list;
        private int startIndex;
        private int endIndex;

        public HandleThread(String threadName, List<String> list, int startIndex, int endIndex) {
            this.threadName = threadName;
            this.list = list;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
        }

        public void run() {
            List<String> subList = list.subList(startIndex, endIndex);
            System.out.println(threadName+"处理了"+subList.size()+"条!startIndex:"+startIndex+"|endIndex:"+endIndex);
        }

    }

    public static void main(String[] args) {
        Test test = new Test();
        List<String> tmpList = new ArrayList<String>();
        for (int i = 0; i < 120; i++) {
            tmpList.add("test" + i);
        }

        int length = tmpList.size();
        int num = 10; //初始线程数

        //启动多线程
        if(num > length){
            num = length;
        }
        int baseNum = length / num;
        int remainderNum = length % num;
        int end  = 0;
        for (int i = 0; i < num; i++) {
            int start = end ;
            end = start + baseNum;
            if(i == (num-1)){
                end = length;
            }else if( i < remainderNum){
                end = end + 1;
            }
            HandleThread thread = new HandleThread("线程[" + (i + 1) + "] ",  tmpList,start , end);
            thread.start();
        }
        System.out.println("程序结束啦");
    }

}

  控制台输出为:

 

使用了Thread的join()方法后:

public class Test {
    static class HandleThread extends Thread {
        private String threadName;
        private List<String> list;
        private int startIndex;
        private int endIndex;

        public HandleThread(String threadName, List<String> list, int startIndex, int endIndex) {
            this.threadName = threadName;
            this.list = list;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
        }

        public void run() {
            List<String> subList = list.subList(startIndex, endIndex);
            System.out.println(threadName+"处理了"+subList.size()+"条!startIndex:"+startIndex+"|endIndex:"+endIndex);
        }

    }

    public static void main(String[] args) {
        Test test = new Test();
        List<String> tmpList = new ArrayList<String>();
        for (int i = 0; i < 120; i++) {
            tmpList.add("test" + i);
        }

        int length = tmpList.size();
        int num = 10; //初始线程数

        //启动多线程
        if(num > length){
            num = length;
        }

        List<HandleThread> handleThreadList = new ArrayList<>();
        int baseNum = length / num;
        int remainderNum = length % num;
        int end  = 0;
        for (int i = 0; i < num; i++) {
            int start = end ;
            end = start + baseNum;
            if(i == (num-1)){
                end = length;
            }else if( i < remainderNum){
                end = end + 1;
            }
            HandleThread thread = new HandleThread("线程[" + (i + 1) + "] ",  tmpList,start , end);
            thread.start();

            handleThreadList.add(thread);
        }
        for(HandleThread handleThread:handleThreadList){
            try {
                handleThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("所有线程都结束啦");
    }
}

 

   控制台输出:

 使用CountDownLatch 方式:

public class Test {
    static class HandleThread extends Thread {
        private String threadName;
        private List<String> list;
        private int startIndex;
        private int endIndex;
        private CountDownLatch countDownLatch;

        public HandleThread(String threadName, List<String> list, int startIndex, int endIndex, CountDownLatch countDownLatch) {
            this.threadName = threadName;
            this.list = list;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.countDownLatch = countDownLatch;
        }

        public void run() {
            List<String> subList = list.subList(startIndex, endIndex);
            System.out.println(threadName+"处理了"+subList.size()+"条!startIndex:"+startIndex+"|endIndex:"+endIndex);
            countDownLatch.countDown();
        }

    }

    public static void main(String[] args) {
        List<String> tmpList = new ArrayList<>();
        for (int i = 0; i < 120; i++) {
            tmpList.add("test" + i);
        }

        int length = tmpList.size();
        int num = 10; //初始线程数

        //启动多线程
        if(num > length){
            num = length;
        }

        int baseNum = length / num;
        int remainderNum = length % num;
        int end  = 0;

        CountDownLatch countDownLatch = new CountDownLatch(num);

        for (int i = 0; i < num; i++) {
            int start = end ;
            end = start + baseNum;
            if(i == (num-1)){
                end = length;
            }else if( i < remainderNum){
                end = end + 1;
            }
            HandleThread thread = new HandleThread("线程[" + (i + 1) + "] ",  tmpList,start , end,countDownLatch);
            thread.start();
        }

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("所有线程都结束啦");
    }
}

  控制台输出结果:

 

posted @ 2018-07-18 17:00  一问三不知。  阅读(824)  评论(0编辑  收藏  举报