CountDownLatch与CyclicBarrier简单用法

CountDownLatch简单用法

  • 代码开发中经常遇到这样的场景:某几个任务执行完成后主线程再继续向下执行,其实实现这个功能非常简单下面列出两种方式。
  • 代码如下:示例1

import java.util.concurrent.CountDownLatch;

public class CountDownLaunchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLaunchDemo demo = new CountDownLaunchDemo();
        //1.原始做法
        //demo.test1();
        //2.用countdownlatch
        demo.test2();
        System.out.println("主线程执行完毕");
    }

    private void test1() throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "做一个耗时任务");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread2 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "做一个耗时任务");
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();

    }

    private void test2() throws InterruptedException {
        CountDownLatch launch = new CountDownLatch(2);
        Thread thread1 = new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + "做一个耗时任务");
                Thread.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //减1,最好放到finally里防止异常退出未执行计数器减1操作
                launch.countDown();
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + "做一个耗时任务");
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //减1,最好放到finally里防止异常退出未执行计数器减1操作
                launch.countDown();
            }
        });

        thread1.start();
        thread2.start();
        //阻塞直到减为0继续向下执行
        launch.await();

    }
}

test1使用原始方式实现的,test2使用CountDownLatch实现的。test1,test2控制台输出如下:

Thread-1做一个耗时任务
Thread-0做一个耗时任务
主线程执行完毕

CyclicBarrier简单用法

当某几个任务执行完成后再执行其它任务,用CyclicBarrier可以轻松实现。
先看下代码:示例2

public class CycliBarrierDemo {
    public static void main(String[] args) throws InterruptedException {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
            @Override
            public void run() {
                System.out.println("两个线程都执行完成");
            }
        });
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程" + Thread.currentThread().getName() + "执行");
                try {
                    Thread.sleep(2000);
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }

            }
        });
        thread1.start();

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程" + Thread.currentThread().getName() + "执行");
                try {
                    Thread.sleep(4000);
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        });
        thread2.start();

        thread1.join();
        thread2.join();
        System.out.println("主线程执行成功!");
    }
}

控制台输出:

线程Thread-0执行
线程Thread-1执行
两个线程都执行完成
主线程执行成功!
  • 当thread1和thread2都执行完成时会执行回调cyclicBarrier 构造函数传进去的方法,这就能够实现当两个任务执行完成再执行其它任务,如示例2所示。
  • 有些人经常把CyclicBarrier与CountDownLatch混淆在一起,实际上两个工具差别很大,就从使用上来说CountDownLatch一般会在主线程用await()方法等待其它线程执行完毕,其它线程如果任务执行完毕会调用用countDown()方法,当计数器为0时,唤醒主线程的await()方法,示例1说明了这一点。
  • 还有就是直观上CountDownLatch要调用await()和countDown()方法,而CyclicBarrier只调用await()方法
  • 再有CountDownLatch调用countDown直到计数器为0唤醒主线程,计数器不能自动恢复,而CyclicBarrier调用await()后计数器加1操作,直到变为构造函数值(本例为2)后,立即回调构造函数传进去的方法(如示例2所示),并且计数器马上重置为0。下面看下CyclicBarrier自动重置计数器并循环使用,如示例3
    示例3

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CycliBarrierDemo {
    public static void main(String[] args) throws InterruptedException {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
            @Override
            public void run() {
                System.out.println("两个线程都执行完成");
            }
        });
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程" + Thread.currentThread().getName() + "执行");
                try {
                    Thread.sleep(2000);
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }

            }
        });
        thread1.start();

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程" + Thread.currentThread().getName() + "执行");
                try {
                    Thread.sleep(4000);
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        });
        thread2.start();

        Thread thread3 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程" + Thread.currentThread().getName() + "执行");
                try {
                    Thread.sleep(2000);
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }

            }
        });
        thread3.start();
        Thread thread4 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程" + Thread.currentThread().getName() + "执行");
                try {
                    Thread.sleep(2000);
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }

            }
        });
        thread4.start();

        thread1.join();
        thread2.join();
        thread3.join();
        thread4.join();
        System.out.println("主线程执行成功!");
    }
}

控制台输出:

线程Thread-0执行
线程Thread-1执行
线程Thread-2执行
线程Thread-3执行
两个线程都执行完成
两个线程都执行完成
主线程执行成功!

可以看出控制台输出了两次“两个线程都执行完成”,证明CyclicBarrier可以循环使用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值