Java 多线程等待优雅的实现方式之Phaser同步屏障

前言

是否会遇到这样的场景,你向线程池提交了多个任务,你希望这批任务全部完成后能够反向通知你。

你可能会使用线程计数的方式,等到计数器累加到提交的线程数量,然后通知。emmm,不是不可以,只是不够优雅。本文提供优雅的实现方式,Phaser同步屏障。

Maven依赖

也可以不依赖,本人习惯把代码简单化,使用了hutool,所以依赖只有这个。

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.15</version>
        </dependency>

代码

废话不多说,上代码。

package com.huyi.csdn.tools;

import cn.hutool.core.thread.ThreadUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;

/**
 * @Program: csdn @ClassName: PhaserUtil @Author: huyi @Date: 2021-11-06 21:03 @Description:
 * 多线程监控回调工具 @Version: V1.0
 */
public class PhaserUtil {
  public static final ExecutorService executorService = Executors.newFixedThreadPool(50);

  public static class CustomPharser extends Phaser {
    private final Runnable runnable;

    public CustomPharser(Runnable runnable) {
      this.runnable = runnable;
    }

    @Override
    protected boolean onAdvance(int phase, int registeredParties) {
      this.runnable.run();
      return super.onAdvance(phase, registeredParties);
    }
  }

  /**
   * 提交任务以及完成后需要执行的内容
   *
   * @param tasks 任务
   * @param complete 完成任务
   */
  public static void submit(List<Runnable> tasks, Runnable complete) {
    Phaser phaser = new CustomPharser(complete);
    for (Runnable runnable : tasks) {
      executorService.submit(
          () -> {
            phaser.register();
            runnable.run();
            System.out.println(Thread.currentThread().getName() + "完成任务!");
            phaser.arriveAndAwaitAdvance();
          });
    }
  }

  /** 摧毁线程池 */
  public static void destroy() {
    System.out.println("摧毁线程池");
    executorService.shutdown();
  }

  public static void main(String[] args) {
    List<Runnable> tasks = new ArrayList<>();
    Random random = new Random();
    for (int i = 0; i < 10; i++) {
      tasks.add(
          () -> {
            ThreadUtil.sleep(random.nextInt(10), TimeUnit.SECONDS);
          });
    }
    submit(tasks, () -> System.out.println("所有任务已完成"));
    ThreadUtil.sleep(20, TimeUnit.SECONDS);
    destroy();
  }
}

代码说明

1、提交任务执行的方式是Runnable也好,Callable也好,或者Consumer、Function等等,不影响,你可以看着调整。

2、完成后的Runnable也和第一点同理。

验证一下

OK,没什么问题。

总结

其实我一直想分享一些可以让读者工作中能用到的东西,想到牧神记里面的一句话,圣人之道,无非就是百姓日用。emmmm,又废话了。

分享一下:

没必要的事就不做,必要的事就尽快做。---冰果

如果本文对你有用,请不要吝啬你的赞,谢谢。

以上就是Java 多线程等待优雅的实现方式之Phaser同步屏障的详细内容,更多关于Java 多线程等待的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解java中的互斥锁信号量和多线程等待机制

    互斥锁和信号量都是操作系统中为并发编程设计基本概念,互斥锁和信号量的概念上的不同在于,对于同一个资源,互斥锁只有0和1 的概念,而信号量不止于此.也就是说,信号量可以使资源同时被多个线程访问,而互斥锁同时只能被一个线程访问 互斥锁在java中的实现就是 ReetranLock , 在访问一个同步资源时,它的对象需要通过方法 tryLock() 获得这个锁,如果失败,返回 false,成功返回true.根据返回的信息来判断是否要访问这个被同步的资源.看下面的例子 public class Reen

  • java多线程之Phaser的使用详解

    前面的文章中我们讲到了CyclicBarrier.CountDownLatch的使用,这里再回顾一下CountDownLatch主要用在一个线程等待多个线程执行完毕的情况,而CyclicBarrier用在多个线程互相等待执行完毕的情况. Phaser是java 7 引入的新的并发API.他引入了新的Phaser的概念,我们可以将其看成一个一个的阶段,每个阶段都有需要执行的线程任务,任务执行完毕就进入下一个阶段.所以Phaser特别适合使用在重复执行或者重用的情况. 基本使用 在CyclicBar

  • Java 多线程等待优雅的实现方式之Phaser同步屏障

    前言 是否会遇到这样的场景,你向线程池提交了多个任务,你希望这批任务全部完成后能够反向通知你. 你可能会使用线程计数的方式,等到计数器累加到提交的线程数量,然后通知.emmm,不是不可以,只是不够优雅.本文提供优雅的实现方式,Phaser同步屏障. Maven依赖 也可以不依赖,本人习惯把代码简单化,使用了hutool,所以依赖只有这个. <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool

  • 深入分析JAVA 多线程--interrupt()和线程终止方式

    一.interrupt() 介绍 interrupt() 定义在 Thread 类中,作用是中断本线程. 本线程中断自己是被允许的:其它线程调用本线程的 interrupt() 方法时,会通过 checkAccess() 检查权限.这有可能抛出 SecurityException 异常. 如果本线程是处于阻塞状态:调用线程的 wait() , wait(long) 或 wait(long, int) 会让它进入等待(阻塞)状态,或者调用线程的 join(),join(long),join(lon

  • 分享Java多线程实现的四种方式

    目录 以下四种方式: 1.继承Thread类,重写run方法 2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target 3.通过Callable和FutureTask创建线程 4.通过线程池创建线程 后面两种可以归结成一类:有返回值,通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中. 第一种:继承Thread类,重写该类的run()方法. class My

  • Java多线程实现的两种方式

    java多线程实现方式主要有两种:继承Thread类.实现Runnable接口 1.继承Thread类实现多线程 继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法.start()方法是一个native方法,它将启动一个新线程,并执行run()方法.这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法

  • 详细解读JAVA多线程实现的三种方式

    最近在做代码优化时学习和研究了下JAVA多线程的使用,看了菜鸟们的见解后做了下总结. 1.继承Thread类实现多线程 继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法.start()方法是一个native方法,它将启动一个新线程,并执行run()方法.这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run(

  • Java多线程三种主要实现方式解析

    多线程三种主要实现方式:继承Thread类,实现Runnable接口.Callable和Futrue. 一.简单实现 import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; public class T02_HowToCreat

  • Java多线程优化方法及使用方式

    一.多线程介绍 在编程中,我们不可逃避的会遇到多线程的编程问题,因为在大多数的业务系统中需要并发处理,如果是在并发的场景中,多线程就非常重要了.另外,我们在面试的时候,面试官通常也会问到我们关于多线程的问题,如:如何创建一个线程?我们通常会这么回答,主要有两种方法,第一种:继承Thread类,重写run方法:第二种:实现Runnable接口,重写run方法.那么面试官一定会问这两种方法各自的优缺点在哪,不管怎么样,我们会得出一个结论,那就是使用方式二,因为面向对象提倡少继承,尽量多用组合. 这个

  • 简单了解Java多线程实现的四种方式

    第一种方式为继承Thread类然后重写run方法再调用start方法,因为java为单继承多实现,所以不建议使用这种方式,代码如下: public class Demo extends Thread{ public static void main(String[] args) { new Demo().start(); } @Override public void run() { System.out.println("继承Thread类实现多线程"); } } 第二种为实现Run

  • java多线程使用mdc追踪日志方式

    目录 多线程使用mdc追踪日志 背景 解决方案 实现 参考 多线程日志追踪 1.问题描述 2. 代理实现日志追踪 多线程使用mdc追踪日志 背景 多线程情况下,子线程的sl4j打印日志缺少traceId等信息,导致定位问题不方便 解决方案 打印日志时添加用户ID.trackId等信息,缺点是每个日志都要手动添加 使用mdc直接拷贝父线程值 实现 // 新建线程时: Map<String, String> mdcContextMap = MDC.getCopyOfContextMap() //

  • java多线程开启的三种方式你知道吗

    目录 1.继承Thread类,新建一个当前类对象,并且运行其start()方法 2.实现Runnable接口,然后新建当前类对象,接着新建Thread对象时把当前类对象传进去,最后运行Thread对象的start()方法 3.实现Callable接口,新建当前类对象,在新建FutureTask类对象时传入当前类对象,接着新建Thread类对象时传入FutureTask类对象,最后运行Thread对象的start()方法 总结 1.继承Thread类,新建一个当前类对象,并且运行其start()方

随机推荐