CyclicBarrier线程同步共享变量底层原理示例解析

 更新时间:2023年07月14日 10:01:43   作者:今夜有点儿凉  
这篇文章主要为大家介绍了CyclicBarrier线程同步共享变量底层原理示例解析详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

CyclicBarrier是Java.util.concurrent包中提供的另一个同步工具类,它允许一组线程在某个共同点处相互等待,并在所有线程都达到某个条件时继续执行。

CyclicBarrier的代码示例

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
    public static void main(String[] args) {
        int workerCount = 3;
        Runnable barrierAction = () -> System.out.println("All workers have reached the barrier.");
        CyclicBarrier cyclicBarrier = new CyclicBarrier(workerCount, barrierAction);
        for (int i = 0; i < workerCount; i++) {
            Thread worker = new Thread(new Worker(cyclicBarrier));
            worker.start();
        }
    }
    static class Worker implements Runnable {
        private final CyclicBarrier cyclicBarrier;
        public Worker(CyclicBarrier cyclicBarrier) {
            this.cyclicBarrier = cyclicBarrier;
        }
        @Override
        public void run() {
            try {
                // 模拟工作任务的执行
                Thread.sleep(2000);
                System.out.println("Worker " + Thread.currentThread().getId() + " has reached the barrier.");
                cyclicBarrier.await(); // 工作线程到达屏障,等待其他线程
                System.out.println("Worker " + Thread.currentThread().getId() + " continues its work.");
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

打印结果:

Worker 13 has reached the barrier.
Worker 14 has reached the barrier.
Worker 12 has reached the barrier.
All workers have reached the barrier.
Worker 14 continues its work.
Worker 13 continues its work.
Worker 12 continues its work.

首先,创建了一个CyclicBarrier对象cyclicBarrier,并指定workerCount为3(代表需要等待的线程数),并设置barrierAction为一个Runnable,用于在所有线程到达屏障时执行。

然后,使用一个for循环创建了3个工作线程(Worker),每个工作线程在完成一部分任务后都会调用await()方法来等待其他线程。在工作线程内部,它们会先模拟一段工作任务的执行,然后调用cyclicBarrier.await()方法等待其他线程。

当所有的工作线程都到达屏障时,即达到指定的workerCount时,它们就会继续执行后续的任务。CyclicBarrier会自动重置计数器,可以继续使用。

在示例中,为了模拟工作任务的执行,工作线程通过Thread.sleep(2000)来暂停2秒钟。然后,每个工作线程输出自己到达屏障的信息,等待其他线程。当所有线程都到达屏障时,会执行设置的barrierAction,即输出所有工作线程都到达了屏障。在此之后,工作线程会继续执行后续的工作任务。

小结:

CyclicBarrier可以用于在多个线程中实现同步,当所有线程都到达屏障时,才能继续执行后续的任务。它常用于需要等待所有线程完成一定阶段的任务后再进行下一阶段的场景。

使用CyclicBarrier示例 模拟收集龙珠的场景

当收集到7颗龙珠后,会触发一个动作(召唤神龙)。

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            System.out.println("召唤神龙");
        });
        for (int i = 1; i <= 7; i++) {
            final int temp = i;
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "\t 收集到第" + temp + "颗龙珠");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
    }
}

在这个示例中,我们创建了一个 CyclicBarrier 对象,指定计数器的值为 7,当 7 个线程都调用了 await() 方法后,会触发传入的 Runnable 对象,即召唤神龙的动作。

在 for 循环中,我们创建了 7 个线程,并分别模拟收集到不同的龙珠。每个线程执行完收集龙珠的操作后,调用 cyclicBarrier.await() 方法,等待其他线程。

当所有线程都调用了 await() 方法后,CyclicBarrier 中的计数器会达到设定的值,触发召唤神龙的动作。输出结果可能类似于以下内容:

1     收集到第1颗龙珠
2     收集到第2颗龙珠
3     收集到第3颗龙珠
4     收集到第4颗龙珠
5     收集到第5颗龙珠
6     收集到第6颗龙珠
7     收集到第7颗龙珠
召唤神龙

这个示例展示了如何使用 CyclicBarrier 来等待多个工作线程执行完毕,并在所有线程完成后触发一个动作。

CyclicBarrier 底层原理

CyclicBarrier 的底层原理涉及到线程同步和共享变量的操作。

CyclicBarrier 的底层原理是基于 AQS(AbstractQueuedSynchronizer)实现的。 CyclicBarrier 内部维护了一个共享的同步状态(state)和一个等待队列。每个线程在调用 await() 方法时,会将线程加入等待队列,并检查当前状态是否为初始状态。如果是初始状态,则线程会进入休眠状态,等待其他线程的到达。当所有线程都调用 await() 方法后,它们会相互唤醒,继续执行后续的任务。同时,CyclicBarrier 的状态会被重置为初始状态,可以继续使用。这样就实现了线程之间的协调与等待的功能。

在 CyclicBarrier 中,有一个计数器(count)和一个屏障点(barrier)用于实现线程的同步。计数器的初始值由构造函数传入,每当一个线程调用 await() 方法时,计数器的值会减一。当计数器的值变为零时,表示所有线程都已到达屏障点,可以继续执行后续操作。

CyclicBarrier 使用了共享变量和内置的线程同步机制来实现等待和通知的功能。具体来说,它使用了以下几个关键的方法和数据结构:

  • await():线程调用 await() 方法时,会尝试获取内置的锁,然后将计数器的值减一。如果计数器的值不为零,那么线程会被阻塞,等待其他线程到达屏障。如果计数器的值变为零,那么所有在屏障上等待的线程将会被唤醒,可以继续执行后续操作。
  • 内置的同步机制:CyclicBarrier 内部使用了内置的同步机制,如锁、条件变量等,来实现线程的等待和通知机制。
  • 循环使用的特性:与 CountDownLatch 不同,CyclicBarrier 是可以循环使用的。当所有线程都到达屏障后,计数器会被重置为初始值,可以进行下一轮的等待和通知。

在底层实现中,CyclicBarrier 使用了类似于 ReentrantLock 和 Condition 的机制来实现线程的等待和唤醒。当一个线程调用 await() 方法时,它会尝试获取内置的锁,然后检查计数器的值。如果计数器的值不为零,线程会通过条件变量进入等待状态。当计数器的值变为零时,最后一个到达屏障的线程会通过条件变量唤醒其他等待的线程,使它们继续执行。

需要注意的是,CyclicBarrier 是可重入的,即同一个线程可以多次调用 await() 方法等待其他线程到达屏障。只有当所有线程都调用了 await() 方法,计数器的值才会变为零,触发屏障的打开。

总结

CyclicBarrier 的底层原理是通过共享变量和内置的线程同步机制来实现线程的等待和通知。它提供了一种循环使用的屏障机制,可以在某个屏障点上同步等待,然后同时继续执行后续的任务。

以上就是CyclicBarrier线程同步共享变量底层原理示例解析的详细内容,更多关于CyclicBarrier线程同步共享变量的资料请关注脚本之家其它相关文章!

相关文章

  • Spring Boot 单元测试和集成测试实现详解

    Spring Boot 单元测试和集成测试实现详解

    这篇文章主要介绍了Spring Boot 单元测试和集成测试实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • java实现贪吃蛇游戏代码(附完整源码)

    java实现贪吃蛇游戏代码(附完整源码)

    这篇文章主要介绍了java实现贪吃蛇游戏代码(附完整源码),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • Java 数据结构与算法系列精讲之哈希算法实现

    Java 数据结构与算法系列精讲之哈希算法实现

    哈希表本质是一种(key,value)结构,由此我们可以联想到,能不能把哈希表的key映射成数组的索引index呢?如果这样做的话那么查询相当于直接查询索引,查询时间复杂度为O(1),其实这也正是当key为int型时的做法,将key通过某种做法映射成index,从而转换成数组结构
    2022-02-02
  • Java打包Jar包后使用脚本执行

    Java打包Jar包后使用脚本执行

    本文详细讲解了Java打包Jar包后使用脚本执行的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-12-12
  • JAVA复制数组和重置数组大小操作

    JAVA复制数组和重置数组大小操作

    这篇文章主要介绍了JAVA复制数组和重置数组大小操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • 老生常谈Log4j和Log4j2的区别(推荐)

    老生常谈Log4j和Log4j2的区别(推荐)

    下面小编就为大家带来老生常谈Log4j和Log4j2的区别(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • 详解Spring中Bean的加载的方法

    详解Spring中Bean的加载的方法

    本篇文章主要介绍了Spring中Bean的加载的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • Maven插件的安装及使用

    Maven插件的安装及使用

    这篇文章主要介绍了Maven插件的安装及使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • 使用@RequiredArgsConstructor注解来取代繁琐的@Autowrired

    使用@RequiredArgsConstructor注解来取代繁琐的@Autowrired

    有了@RequiredArgsConstructor注解,我们就可以减少@Autowired的书写,本文主要介绍了使用@RequiredArgsConstructor注解来取代繁琐的@Autowrired,感兴趣的可以了解一下
    2022-04-04
  • java必懂的冷知识点之Base64加密与解密

    java必懂的冷知识点之Base64加密与解密

    这篇文章主要介绍了java必懂的冷知识点之Base64加密与解密的相关资料,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03

最新评论