JAVA CyclicBarrier 示例源码解析

 更新时间:2023年12月18日 15:17:40   作者:fking86  
CyclicBarrier是一个强大的同步工具,可以帮助我们实现复杂的多线程协同任务,这篇文章主要介绍了JAVA CyclicBarrier 示例源码解析,通过本文,我们深入了解了CyclicBarrier的源码实现,并通过一个简单的示例演示了它的用法,需要的朋友可以参考下

前言

在多线程编程中,同步工具是确保线程之间协同工作的重要组成部分。

CyclicBarrier(循环屏障)是Java中的一个强大的同步工具,它允许一组线程在达到某个共同点之前互相等待。

在本文中,我们将深入探讨CyclicBarrier的源码实现以及提供一些示例,以帮助您更好地理解和应用这个有趣的同步工具。

CyclicBarrier源码解析以及示例

主要成员变量

public class CyclicBarrier {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition trip = lock.newCondition();
    private final int parties;
    private int count;
    private final Runnable barrierCommand;
}
  • lock: 用于控制并发访问的重入锁。
  • trip: 条件变量,用于在屏障点上等待。
  • parties: 表示需要等待的线程数。
  • count: 表示当前已经到达屏障点的线程数。
  • barrierCommand: 在所有线程到达屏障点之后执行的命令,可以为null。

核心方法

await方法

public int await() throws InterruptedException, BrokenBarrierException {
    try {
        lock.lock();
        if (Thread.interrupted())
            throw new InterruptedException();
        int index = --count;
        if (index == 0) { // 如果是最后一个到达的线程
            boolean ranAction = false;
            try {
                final Runnable command = barrierCommand;
                if (command != null)
                    command.run();
                ranAction = true;
                return 0;
            } finally {
                if (!ranAction)
                    breakBarrier(); // 执行失败,重置屏障状态
            }
        }
        while (index > 0) {
            try {
                trip.await();
            } catch (InterruptedException ie) {
                if (index == 1 && !broken)
                    breakBarrier();
                throw ie;
            }
        }
        if (broken)
            throw new BrokenBarrierException();
        return index;
    } finally {
        lock.unlock();
    }
}

上述代码主要完成以下几个任务:

  • 减小计数器,表示有一个线程到达了屏障点。
  • 如果是最后一个到达的线程,执行屏障命令(如果有),然后唤醒所有等待的线程。
  • 如果不是最后一个到达的线程,进入等待状态,直到被唤醒。
  • 处理中断异常和屏障破坏异常。

应用场景

任务分解与合并

当一个大任务可以分解为多个子任务,每个子任务独立执行,但在某个点上需要等待所有子任务完成后再继续执行父任务。CyclicBarrier可以用来同步这些子任务的执行,确保它们在特定的屏障点上等待,然后一起继续执行。

应用示例

假设我们有一个大型的数据处理任务,需要将数据分解为若干子任务并行处理,然后在所有子任务完成后进行结果的合并。CyclicBarrier 可以用来同步子任务的执行,确保在所有子任务都完成后再进行合并操作。

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class TaskDecompositionAndMergeExample {
    private static final int NUM_SUBTASKS = 3;
    private static final CyclicBarrier barrier = new CyclicBarrier(NUM_SUBTASKS, () -> {
        System.out.println("All subtasks have been completed. Merging results...");
    });
    public static void main(String[] args) {
        for (int i = 0; i < NUM_SUBTASKS; i++) {
            final int subtaskId = i;
            new Thread(() -> {
                // Perform individual subtask
                System.out.println("Subtask " + subtaskId + " is processing.");
                // Simulate some computation for the subtask
                try {
                    Thread.sleep((long) (Math.random() * 1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Subtask " + subtaskId + " has completed.");
                try {
                    // Wait for all subtasks to complete
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

并行计算

在并行计算中,当多个计算节点完成局部计算后,需要将它们的结果合并。CyclicBarrier可以用来等待所有计算节点完成局部计算,然后执行合并操作。

应用示例

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class ParallelComputingExample {
    private static final int NUM_THREADS = 4;
    private static final CyclicBarrier barrier = new CyclicBarrier(NUM_THREADS, () -> {
        System.out.println("All threads have completed the computation. Merging results...");
    });
    public static void main(String[] args) {
        for (int i = 0; i < NUM_THREADS; i++) {
            final int threadId = i;
            new Thread(() -> {
                // Perform individual computation
                System.out.println("Thread " + threadId + " is performing computation.");
                // Simulate some computation for the thread
                try {
                    Thread.sleep((long) (Math.random() * 1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread " + threadId + " has completed computation.");
                try {
                    // Wait for all threads to complete computation
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

游戏开发

在多线程游戏开发中,可能存在多个线程分别负责不同的任务,比如渲染、物理模拟、AI计算等。

在每一帧结束时,这些线程需要同步,确保下一帧开始时所有任务都已完成。CyclicBarrier可以在每一帧结束时等待所有任务完成,然后统一开始下一帧的计算。

比如我们在打匹配游戏的时候,十个人必须全部加载到100%,才可以开局。否则只要有一个人没有加载到100%,那这个游戏就不能开始。先加载完成的玩家必须等待最后一个玩家加载成功才可以。

应用示例

public class CyclicBarrierDemo {
    private static CyclicBarrier cyclicBarrier;
    static class CyclicBarrierThread extends Thread{
        @Override
        public void run() {
            System.out.println("玩家 " + Thread.currentThread().getName() + " 加载100%");
            //等待
            try {
                cyclicBarrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args){
        cyclicBarrier = new CyclicBarrier(10, new Runnable() {
            public void run() {
                System.out.println("玩家都加载好了,开始游戏....");
            }
        });
        for(int i = 0 ; i < 10 ; i++){
            new CyclicBarrierThread().start();
        }
    }
}

输出结果

玩家 Thread-0 加载100%
玩家 Thread-2 加载100%
玩家 Thread-3 加载100%
玩家 Thread-6 加载100%
玩家 Thread-1 加载100%
玩家 Thread-4 加载100%
玩家 Thread-5 加载100%
玩家 Thread-8 加载100%
玩家 Thread-7 加载100%
玩家 Thread-9 加载100%
玩家都加载好了,开始游戏....

数据加载

在某些应用中,可能需要同时加载多个数据源,但要确保所有数据加载完成后再继续执行。CyclicBarrier可以用来等待所有数据加载完成,然后执行后续操作。

应用示例

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class DataLoaderExample {
    private static final int NUM_THREADS = 3;
    private static final CyclicBarrier barrier = new CyclicBarrier(NUM_THREADS, () -> {
        System.out.println("All data loading threads have completed. Initiating further processing...");
    });
    public static void main(String[] args) {
        for (int i = 0; i < NUM_THREADS; i++) {
            final int threadId = i;
            new Thread(() -> {
                // Simulate data loading
                System.out.println("Thread " + threadId + " is loading data.");
                // Simulate data loading time
                try {
                    Thread.sleep((long) (Math.random() * 1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread " + threadId + " has completed data loading.");
                try {
                    // Wait for all data loading threads to complete
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                // Perform further processing after data loading is complete
                System.out.println("Thread " + threadId + " is performing further processing.");
            }).start();
        }
    }
}

并发工具的协同

CyclicBarrier可以与其他并发工具一起使用,例如 ExecutorServiceCountDownLatch,以实现更复杂的多线程控制逻辑。

应用示例

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
    private static final int NUM_THREADS = 3;
    private static final CyclicBarrier barrier = new CyclicBarrier(NUM_THREADS, () -> {
        System.out.println("All threads have reached the barrier. Let's continue!");
    });
    public static void main(String[] args) {
        for (int i = 0; i < NUM_THREADS; i++) {
            new Thread(() -> {
                try {
                    // Perform individual tasks
                    System.out.println(Thread.currentThread().getName() + " is performing individual tasks.");
                    // Wait for all threads to reach the barrier
                    barrier.await();
                    // Continue with collective tasks after reaching the barrier
                    System.out.println(Thread.currentThread().getName() + " is performing collective tasks.");
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

CyclicBarrier和CountDownLatch的区别

循环性:

  • CyclicBarrier 具有循环的特性,可以被重复使用。一旦所有线程都到达屏障点,它会自动重置并再次等待下一轮。这使得 CyclicBarrier 更适合用于一组线程多次协同工作的场景。
  • CountDownLatch 是一次性的,一旦计数到达零,就无法重新设置。如果需要多次等待,就需要创建新的 CountDownLatch 实例。

计数器的变化:

  • CyclicBarrier 中,计数器的递减是由到达屏障点的线程执行的,而且在所有线程都到达之前,任何线程都不会继续执行。
  • CountDownLatch 中,计数器的递减是由任意线程执行的,而且线程在递减计数器后可以继续执行,不必等待其他线程。

用途:

  • CyclicBarrier 通常用于一组线程并行执行任务,然后在某个点上等待彼此,然后再一起继续执行下一轮任务。例如,任务分解与合并、并行计算等场景。
  • CountDownLatch 用于等待一组线程完成某个任务后再执行其他任务。例如,主线程等待所有工作线程完成工作后再继续执行。

构造函数参数:

  • CyclicBarrier 的构造函数需要指定参与同步的线程数,以及在屏障点上执行的可选操作(Runnable)。
  • CountDownLatch 的构造函数需要指定计数的初始值。

总结

通过本文,我们深入了解了CyclicBarrier的源码实现,并通过一个简单的示例演示了它的用法。

CyclicBarrier是一个强大的同步工具,可以帮助我们实现复杂的多线程协同任务。

在多线程编程中,理解和熟练使用这样的同步工具是至关重要的,能够确保线程之间的协同工作更加高效和可靠。

到此这篇关于JAVA CyclicBarrier 示例源码解析的文章就介绍到这了,更多相关JAVA CyclicBarrier内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Hibernate中5个核心接口知识点整理

    Hibernate中5个核心接口知识点整理

    在本篇文章里小编给大家整理的是一篇关于Hibernate中5个核心接口知识点整理等内容,有兴趣的朋友们跟着学习参考下。
    2021-08-08
  • 简单分析java中CMS回收器

    简单分析java中CMS回收器

    在本篇文章里我们给大家分享了关于java中CMS回收器的相关知识点内容,有需要的朋友们可以跟着学习下。
    2018-10-10
  • Java回调机制解读

    Java回调机制解读

    本文主要介绍了Java回调机制的相关知识,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • java中动态代理的实现

    java中动态代理的实现

    本篇文章主要介绍了Java中两种动态代理的实现:jdk动态代理;cglib动态代理。具有一定的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • Java中JDBC事务与JTA分布式事务总结与区别

    Java中JDBC事务与JTA分布式事务总结与区别

    Java事务的类型有三种:JDBC事务、JTA(Java Transaction API)事务、容器事务,本文详细介绍了JDBC事务与JTA分布式事务,有需要的可以了解一下。
    2016-11-11
  • Java中的线程中断机制和LockSupport详解

    Java中的线程中断机制和LockSupport详解

    这篇文章主要介绍了Java中的线程中断机制和LockSupport详解,在Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作,因此,Java提供了一种用于停止线程的协商机制中断,也即中断标识协商机制,需要的朋友可以参考下
    2023-09-09
  • Java 全方位讲解面向对象特点与使用

    Java 全方位讲解面向对象特点与使用

    面向对象开发方法将面向对象的思想应用于软件开发过程中,指导开发活动,是建立在“对象”概念基础上的方法学,简称OO( Object-Oriented)方法
    2022-04-04
  • springmvc实现自定义类型转换器示例

    springmvc实现自定义类型转换器示例

    本篇文章主要介绍了springmvc实现自定义类型转换器示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • 关于SpringBoot中事务失效的几种情况

    关于SpringBoot中事务失效的几种情况

    这篇文章主要介绍了关于SpringBoot中事务失效的几种情况,Spring AOP默认使用动态代理,会给被代理的类生成一个代理类,事务相关的操作都通过代理来完成,使用内部方法调用时,使用的是实例调用,没有通过代理类调用方法,因此事务不会检测到失败,需要的朋友可以参考下
    2023-08-08
  • Java JVM原理与调优_动力节点Java学院整理

    Java JVM原理与调优_动力节点Java学院整理

    JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。下面通过本文给大家介绍jvm原理与调优相关知识,感兴趣的朋友一起学习吧
    2017-04-04

最新评论