java多线程中CountDownLatch和join的使用

在工作中,我们经常需要和多线程打交道,简单说明一个场景,在工厂流水线上有2条流水线,流水线同时开工生产零件,但是每个零件生产时间不一样,只有等到两个零件都生产完毕之后才能开始总组装。那我们很快想到join就能做到。例如子线程thread调用了join,那么在子线程thread还存活的时候,让当前线程wait,直到thread死亡,就会调用当前线程的notifyAll方法。

简单用一个小例子来说明一下,现在有两个工作线程,分别给一个随机的工作时间t,然后在线程中给这个随机的工作时间+1s得到时间T;等到两个工作线程执行完毕之后,我们再执行第三个线程,这两个时间T加起来就是第三个线程的工作时间。那看一下代码和执行结果。

public class JoinTest {
    public static void main(String[] args) {
        WorkThread work_one = new WorkThread("work one", new Random().nextInt(10));
        WorkThread work_two = new WorkThread("work two", new Random().nextInt(10));
        work_one.start();
        work_two.start();

        try {
            work_one.join();
            work_two.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("准备工作做完,可以开始干正事");


        WorkThread work_mian = new WorkThread("work main", work_one.getWorkTime() + work_two.getWorkTime());
        work_mian.start();
    }

    private static class WorkThread extends Thread {
        private int WorkTime;
        private String WorkName;

        public int getWorkTime() {
            return WorkTime;
        }

        public WorkThread(String WorkName, int WorkTime) {
            this.WorkName = WorkName;
            this.WorkTime = WorkTime;
            System.out.println(WorkName + " initialize time = " + WorkTime);
        }

        @Override
        public void run() {
            try {
                System.out.println(WorkName + " start work...");
                WorkTime = WorkTime + 1;
                Thread.sleep(1000 * WorkTime);
                System.out.println(WorkName + " complete work WorkTime = " + WorkTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println(WorkName + " error work...");
            }
        }
    }
}

执行结果:

work one initialize time = 3
work two initialize time = 4
work one start work...
work two start work...
work one complete work WorkTime = 4
work two complete work WorkTime = 5
准备工作做完,可以开始干正事
work main initialize time = 9
work main start work...

work main complete work WorkTime = 10

那在jdk1.5之后,我们引入了CountDownLatch,CountDownLatch的原理就是先初始化执行线程的个数,执行完我们的工作之后就手动减一,等到读取的个数为0的时候,就开始总的工作。我们也用同样的场景来写一份代码。

public class CountDownLatchTest {

    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(2);
        WorkThread work_one = new WorkThread("work one", new Random().nextInt(10), countDownLatch);
        WorkThread work_two = new WorkThread("work two", new Random().nextInt(10), countDownLatch);
        work_one.start();
        work_two.start();

        //等待结果
        try {
            countDownLatch.await();
            System.out.println("准备工作做完,可以开始干正事");
            WorkThread work_main = new WorkThread("work main", work_one.getWorkTime() + work_two.getWorkTime(), null);
            work_main.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static class WorkThread extends Thread {
        private int WorkTime;
        private String WorkName;
        private CountDownLatch countDownLatch;

        public int getWorkTime() {
            return WorkTime;
        }

        public WorkThread(String WorkName, int WorkTime, CountDownLatch countDownLatch) {
            this.WorkName = WorkName;
            this.WorkTime = WorkTime;
            this.countDownLatch = countDownLatch;
            System.out.println(WorkName + " initialize time = " + WorkTime);
        }

        @Override
        public void run() {
            try {
                System.out.println(WorkName + " start work...");
                WorkTime = WorkTime + 1;
                Thread.sleep(1000 * WorkTime);
                System.out.println(WorkName + " complete work WorkTime = " + WorkTime);
                //工作完成后减一
                if (countDownLatch != null) {
                    countDownLatch.countDown();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println(WorkName + " error work...");
            }
        }
    }
}

附上执行结果:

work one initialize time = 7
work two initialize time = 8
work one start work...
work two start work...
work one complete work WorkTime = 8
work two complete work WorkTime = 9
准备工作做完,可以开始干正事
work main initialize time = 17
work main start work...

work main complete work WorkTime = 18

当然为什么要提供CountDownLatch呢,不是有join就够了吗。那我们看下第二个场景,这个是join做不到的。因为CountDownLatch带有计数器。比如有一个会议,每个人都要在会议上做笔记,那我们现在由于会议需要提前进行,只要人到了就开始会议,不需要花几分钟带上笔记本,会议之后再做笔记都行。这个时候CountDownLatch就能使用了。我们用代码看一下。

public class CountDownLatchTest {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(10);
        for (int i = 0; i < 10; i++) {
            new WorkThread(String.valueOf(i),new Random().nextInt(10),countDownLatch).start();
        }
        countDownLatch.await();
        System.out.println("会议开始,大家没有做笔记的可以会议之后做笔记了");
    }

    private static class WorkThread extends Thread {
        private int WorkTime;
        private String WorkName;
        private CountDownLatch countDownLatch;

        public int getWorkTime() {
            return WorkTime;
        }

        public WorkThread(String WorkName, int WorkTime, CountDownLatch countDownLatch) {
            this.WorkName = WorkName;
            this.WorkTime = WorkTime;
            this.countDownLatch = countDownLatch;
            System.out.println(WorkName + " initialize time = " + WorkTime);
        }

        @Override
        public void run() {
            try {
                System.out.println(WorkName + " start work...");
                WorkTime = WorkTime + 1;
                Thread.sleep(1000 * WorkTime);
                System.out.println(WorkName + " complete work step one WorkTime = " + WorkTime);
                //第一阶段 开会   完成后减一
                countDownLatch.countDown();
                //第二阶段   做笔记
                Thread.sleep(5000);
                System.out.println(WorkName + " complete work step two WorkTime = " + WorkTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println(WorkName + " error work...");
            }
        }
    }
}

执行结果:

0 initialize time = 6
1 initialize time = 6
2 initialize time = 1
0 start work...
3 initialize time = 9
2 start work...
1 start work...
4 initialize time = 7
3 start work...
5 initialize time = 7
4 start work...
5 start work...
6 initialize time = 3
7 initialize time = 6
6 start work...
8 initialize time = 9
7 start work...
9 initialize time = 2
8 start work...
9 start work...
2 complete work step one WorkTime = 2
9 complete work step one WorkTime = 3
6 complete work step one WorkTime = 4
1 complete work step one WorkTime = 7
0 complete work step one WorkTime = 7
7 complete work step one WorkTime = 7
2 complete work step two WorkTime = 2
9 complete work step two WorkTime = 3
4 complete work step one WorkTime = 8
5 complete work step one WorkTime = 8
6 complete work step two WorkTime = 4
8 complete work step one WorkTime = 10
3 complete work step one WorkTime = 10
会议开始,大家没有做笔记的可以会议之后做笔记了
7 complete work step two WorkTime = 7
0 complete work step two WorkTime = 7
1 complete work step two WorkTime = 7
4 complete work step two WorkTime = 8
5 complete work step two WorkTime = 8
8 complete work step two WorkTime = 10

3 complete work step two WorkTime = 10

从结果可以看出有一部分是边开会边做笔记的,有一部分是会议结束之后做笔记的。这就是CountDownLatch独特的地方。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值