【JAVA并发编程专题】同步屏障CyclicBarrier的理解和使用

简介: 【JAVA并发编程专题】同步屏障CyclicBarrier的理解和使用

正文


一、同步屏障简介


同步屏障CyclicBarrie的作用顾名思义,就是为所有线程设置一个屏障,等大家都同步后,再一起往下执行。比如我们有3个线程A、B、C,都启动后,势必有执行快慢的区别,我们为每个线程设置一个同步点,称为同步屏障。每个线程达到自己的这个同步点之后就进入等待状态,等待最后一个线程也达到同步点之后,大家再从同步点开始往后执行。


二、同步屏障的使用


    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
        // 设置屏障拦截的线程数量为2
        CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                log.info("子线程开始执行...");
                try {
                    cyclicBarrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                log.info("子线程执行结束");
            }
        });
        thread.start();
        log.info("主线程开始执行...");
        TimeUnit.SECONDS.sleep(3);
        cyclicBarrier.await();
        log.info("主线程执行结束");
    }
}


执行结果为:

22:35:29.751 [main] INFO com.example.concurrent.CyclicBarrierTest - 主线程开始执行...
22:35:29.751 [Thread-0] INFO com.example.concurrent.CyclicBarrierTest - 子线程开始执行...
22:35:32.765 [main] INFO com.example.concurrent.CyclicBarrierTest - 主线程执行结束
22:35:32.765 [Thread-0] INFO com.example.concurrent.CyclicBarrierTest - 子线程执行结束

如果上述设置的拦截线程数量为3,那么主线程和子线程达到各自的同步点的时候,都不能再继续往下执行,而是一直再等待着。

还有一种用法,允许子线程在达到自己的同步点的时候,优先去执行另外一个任务,等到这个任务处理完成,子线程和主线程再同步往下执行。

public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new MyThread());
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                log.info("子线程开始执行...");
                try {
                    cyclicBarrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                log.info("子线程执行结束");
            }
        });
        thread.start();
        log.info("主线程开始执行...");
        TimeUnit.SECONDS.sleep(2);
        cyclicBarrier.await();
        log.info("主线程执行结束");
    }
    static class MyThread implements Runnable{
        @Override
        public void run() {
            log.info("myThread运行开始...");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("myThread运行结束");
        }
    }

输出结果如下:

02:16:16.289 [Thread-0] INFO com.example.concurrent.CyclicBarrierTest - 子线程开始执行...
02:16:16.295 [Thread-0] INFO com.example.concurrent.CyclicBarrierTest - myThread运行开始...
02:16:21.296 [Thread-0] INFO com.example.concurrent.CyclicBarrierTest - myThread运行结束
02:16:21.296 [Thread-0] INFO com.example.concurrent.CyclicBarrierTest - 子线程执行结束
02:16:21.297 [main] INFO com.example.concurrent.CyclicBarrierTest - 主线程执行结束

这里的MyThread主要是用来对子线程到达同步点时的运算结果做一些额外的处理工作。


三、CyclicBarrier和CountDownLatch的比较


  • 使用场景不同,CountDownLatch是主线程等待子线程全部countDown之后才可以继续工作,但是不会阻碍子线程的运行;CyclicBarrier是所有线程都到达自己的同步点之后,再一起从各自的同步点往后执行,在这之前,只要有一个线程没有达到同步点,大家都必须等着;
  • CountDownLatch是通过减法计数来实现的,每个计数只能使用一次,不能重复使用;而CyclicBarrier的计数是可以通过reset来重置的,如此可以重复使用,从而能处理更加复杂的业务场景,比如某个线程计算出现错误,可以重置计数,再执行一遍。


相关文章
|
12天前
|
安全 Java 程序员
深入理解Java内存模型与并发编程####
本文旨在探讨Java内存模型(JMM)的复杂性及其对并发编程的影响,不同于传统的摘要形式,本文将以一个实际案例为引子,逐步揭示JMM的核心概念,包括原子性、可见性、有序性,以及这些特性在多线程环境下的具体表现。通过对比分析不同并发工具类的应用,如synchronized、volatile关键字、Lock接口及其实现等,本文将展示如何在实践中有效利用JMM来设计高效且安全的并发程序。最后,还将简要介绍Java 8及更高版本中引入的新特性,如StampedLock,以及它们如何进一步优化多线程编程模型。 ####
20 0
|
14天前
|
Java 程序员
Java编程中的异常处理:从基础到高级
在Java的世界中,异常处理是代码健壮性的守护神。本文将带你从异常的基本概念出发,逐步深入到高级用法,探索如何优雅地处理程序中的错误和异常情况。通过实际案例,我们将一起学习如何编写更可靠、更易于维护的Java代码。准备好了吗?让我们一起踏上这段旅程,解锁Java异常处理的秘密!
|
18天前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
18天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
11天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
11天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
32 3
|
17天前
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
56 6
|
16天前
|
开发框架 安全 Java
Java 反射机制:动态编程的强大利器
Java反射机制允许程序在运行时检查类、接口、字段和方法的信息,并能操作对象。它提供了一种动态编程的方式,使得代码更加灵活,能够适应未知的或变化的需求,是开发框架和库的重要工具。
34 2
|
17天前
|
安全 Java 开发者
Java中的多线程编程:从基础到实践
本文深入探讨了Java多线程编程的核心概念和实践技巧,旨在帮助读者理解多线程的工作原理,掌握线程的创建、管理和同步机制。通过具体示例和最佳实践,本文展示了如何在Java应用中有效地利用多线程技术,提高程序性能和响应速度。
52 1
|
18天前
|
Java API 数据库
Java 反射机制:动态编程的 “魔法钥匙”
Java反射机制是允许程序在运行时访问类、方法和字段信息的强大工具,被誉为动态编程的“魔法钥匙”。通过反射,开发者可以创建更加灵活、可扩展的应用程序。
34 0