线程并发工具类之CountDownLatch

2020-04-06  本文已影响0人  传达室马大爷

CountDownLatch

实例
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;

import com.shawntime.enjoy.architect.concurrency.SleepUtils;

/**
 * countDownLatch:
 */
public class CountDownLatchTest {

    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(6);

        for (int i = 0; i < 4; ++i) {
            InitThread initThread = new InitThread("init-thread-" + i, countDownLatch);
            initThread.start();
        }

        BusinessThread businessThread = new BusinessThread("business-thread", countDownLatch);
        businessThread.start();

        new Thread(() -> {
            {
                try {
                    SleepUtils.sleepBySeconds(1);
                    System.out.println(Thread.currentThread().getName() + " really init worker step 1...");
                } finally {
                    countDownLatch.countDown();
                }
                try {
                    SleepUtils.sleepBySeconds(1);
                    System.out.println(Thread.currentThread().getName() + " really init worker step 2...");
                } finally {
                    countDownLatch.countDown();
                }

            }
        }, "single-thread").start();

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Main do work....");
    }


    /**
     * 初始化线程
     */
    private static class InitThread extends Thread {

        private CountDownLatch countDownLatch;

        public InitThread(String name, CountDownLatch countDownLatch) {
            super(name);
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + " waiting really init...");
                int time = ThreadLocalRandom.current().nextInt(1000);
                SleepUtils.sleepByMilliSeconds(time);
            } finally {
                countDownLatch.countDown();
            }
            for (int i = 0; i < 3; ++i) {
                System.out.println(Thread.currentThread().getName() + " init continue working...");
            }
        }
    }

    /**
     * 业务线程
     */
    private static class BusinessThread extends Thread {

        private CountDownLatch countDownLatch;

        public BusinessThread(String name, CountDownLatch countDownLatch) {
            super(name);
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for (int i = 0; i < 3; ++i) {
                System.out.println(Thread.currentThread().getName() + " business do working...");
            }
        }
    }
}

运行结果:
init-thread-1 waiting really init...
init-thread-0 waiting really init...
init-thread-2 waiting really init...
init-thread-3 waiting really init...
init-thread-0 init continue working...
init-thread-0 init continue working...
init-thread-0 init continue working...
init-thread-1 init continue working...
init-thread-1 init continue working...
init-thread-1 init continue working...
init-thread-2 init continue working...
init-thread-2 init continue working...
init-thread-2 init continue working...
init-thread-3 init continue working...
init-thread-3 init continue working...
init-thread-3 init continue working...
single-thread really init worker step 1...
single-thread really init worker step 2...
Main do work....
business-thread business do working...
business-thread business do working...
business-thread business do working...

结果分析

1、countDownLatch计数器个数为6,则必须等到调用了6次countDown()方法之后主线程和业务线程才会执行
2、主线程和业务线程同时调用了await()方法进行阻塞

countDownLatch()方法和join()方法的区别

实例:实现数据的初始化工作,主线程需要等待线程1、2、3均初始化完成后才能继续执行

countDownLatch()方法实现

import java.util.concurrent.CountDownLatch;

import com.shawntime.enjoy.architect.concurrency.SleepUtils;

public class DataInitForCountDownLatch {

    private static class InitThread extends Thread {

        private CountDownLatch countDownLatch;

        public InitThread(String name, CountDownLatch countDownLatch) {
            super(name);
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            try {
                SleepUtils.sleepByMilliSeconds(100);
                System.out.println(Thread.currentThread().getName() + "线程初始化第一步完成");

                SleepUtils.sleepByMilliSeconds(100);
                System.out.println(Thread.currentThread().getName() + "线程初始化第二步完成");
            } finally {
                countDownLatch.countDown();
            }
        }
    }

    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        for (int i = 1; i < 4; ++i) {
            new InitThread("thread-" + i, countDownLatch).start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("主线程执行....");
    }
}

输出结果:
thread-3线程初始化第一步完成
thread-1线程初始化第一步完成
thread-2线程初始化第一步完成
thread-1线程初始化第二步完成
thread-2线程初始化第二步完成
thread-3线程初始化第二步完成
主线程执行....

join()方法实现

import com.shawntime.enjoy.architect.concurrency.SleepUtils;

public class DataInitForJoin {

    private static class InitThread extends Thread {

        public InitThread(String name) {
            super(name);
        }

        @Override
        public void run() {

            SleepUtils.sleepByMilliSeconds(100);
            System.out.println(Thread.currentThread().getName() + "线程初始化第一步完成");

            SleepUtils.sleepByMilliSeconds(100);
            System.out.println(Thread.currentThread().getName() + "线程初始化第二步完成");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        InitThread initThread1 = new InitThread("thread-1");
        InitThread initThread2 = new InitThread("thread-2");
        InitThread initThread3 = new InitThread("thread-3");

        initThread1.start();
        initThread2.start();
        initThread3.start();

        initThread1.join();
        initThread2.join();
        initThread3.join();

        System.out.println("主线程继续执行....");
    }
}

输出结果:
thread-2线程初始化第一步完成
thread-1线程初始化第一步完成
thread-3线程初始化第一步完成
thread-2线程初始化第二步完成
thread-1线程初始化第二步完成
thread-3线程初始化第二步完成
主线程继续执行....

如果我想在初始化第一步完成结束后主线程就可以继续执行的话,则join()方法无法实现,而countDownLatch则可以轻松的实现

import java.util.concurrent.CountDownLatch;

import com.shawntime.enjoy.architect.concurrency.SleepUtils;

public class DataInitForCountDownLatch {

    private static class InitThread extends Thread {

        private CountDownLatch countDownLatch;

        public InitThread(String name, CountDownLatch countDownLatch) {
            super(name);
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            try {
                SleepUtils.sleepByMilliSeconds(100);
                System.out.println(Thread.currentThread().getName() + "线程初始化第一步完成");
            } finally {
                countDownLatch.countDown();
            }
            SleepUtils.sleepByMilliSeconds(100);
            System.out.println(Thread.currentThread().getName() + "线程初始化第二步完成");
        }
    }

    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        for (int i = 1; i < 4; ++i) {
            new InitThread("thread-" + i, countDownLatch).start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("主线程执行....");
    }
}

输出结果:
thread-1线程初始化第一步完成
thread-3线程初始化第一步完成
thread-2线程初始化第一步完成
主线程执行....
thread-1线程初始化第二步完成
thread-3线程初始化第二步完成
thread-2线程初始化第二步完成

总结:join()方法必须要等到线程结束后才能解除阻塞,而countDownLatch不需要等到线程结束,只要调用了countDown()方法保证计数器个数为0时即可解除阻塞,countDownLatch比join()方法更灵活
上一篇 下一篇

猜你喜欢

热点阅读