Java实现Promise.all()的示例代码

JavaScript的Promise.all()

Promise是JavaScript异步编程的一种解决方案,在ES6中引入。

通过Promise.all()可以实现对一组异步请求的统一处理,等待所有异步执行完成之后调用回调函数。

其实,这种并发执行同步等待的需求在Java并发编程中也很常见,那么,是否可以通过Java也来实现这样一个Promise类呢?

使用Java实现Promise.all()

使用工具

CountDownLatch:Java并发工具包中有CountDownLatch类允许一个或多个线程等待其他线程的一系列操作完成。

ThreadPoolExecutor:通过线程池实现多线程的并发执行

实现

public class Promise {

  private static ExecutorService executorService = Executors.newScheduledThreadPool(16);

  private Promise() {
    throw new AssertionError();
  }

  /**
   * 实现并发同时地对某个action并发执行并返回执行结果
   * 实现思路:
   * 并发创建所有执行的线程,并通过锁(start)阻塞等待着
   * 在创建所有执行的线程后(ready)开始计时,并解锁然所有的线程启动
   * 通过另外一个锁(done)记录执行完的线程
   * 主线程只需关心3点
   * - 所有线程是否准备好
   * - 准备好的话开始计时并解锁开始执行
   * - 等待执行完毕
   *
   * @param callableList 要并发执行的列表
   * @return list 执行结果,list.item为null的话表示执行异常
   * @throws InterruptedException 异常
   */
  public static <T> List<T> all(final List<Callable<T>> callableList) throws InterruptedException {
    final List<T> result = new ArrayList<>();
    int length = callableList.size();
    final CountDownLatch ready = new CountDownLatch(length);
    final CountDownLatch start = new CountDownLatch(1);
    final CountDownLatch done = new CountDownLatch(length);
    for (final Callable<T> callable : callableList) {
      executorService.execute(new Runnable() {
        @Override
        public void run() {
          ready.countDown();
          try {
            start.await();
            T t = callable.call();
            result.add(t);
          } catch (Exception e) {
            // interrupt when exception
            Thread.currentThread().interrupt();
            // set null mean exception
            result.add(null);
            e.printStackTrace();
          } finally {
            done.countDown();
          }
        }
      });
    }
    ready.await();
    long startnano = System.nanoTime();
    start.countDown();
    done.await();
    long cause = System.nanoTime() - startnano;
    System.out.println(String.format("Promise all done,cause time millSecond: %s", cause / 1000000));
    return result;
  }
}

效果

测试

public void promiseAllTest() throws Exception{

  List<Callable<String>> callables = new ArrayList<>();

  for (int i = 0; i < 10; i++) {
    int finalI = i;
    callables.add(new Callable<String>() {
      @Override
      public String call() throws Exception {
        int millis = new Random().nextInt(10000);
        Thread.sleep(millis);
        System.out.println(String.format("thread%s sleep %s millis" ,finalI,millis));
        return "Thread" + finalI;
      }
    });
  }

  List<String> result = Promise.all(callables);

  System.out.println(result);
  System.out.println("done...");

}

测试结果

thread1 sleep 732 millis
thread2 sleep 758 millis
thread7 sleep 976 millis
thread8 sleep 1397 millis
thread5 sleep 1513 millis
thread0 sleep 2221 millis
thread3 sleep 4885 millis
thread6 sleep 5221 millis
thread4 sleep 7101 millis
thread9 sleep 7634 millis
Promise all done,cause time millSecond: 7638
[Thread1, Thread2, Thread7, Thread8, Thread5, Thread0, Thread3, Thread6, Thread4, Thread9]
done...

总结

本文只是通过原生Java实现简单版本的Promise.all(),可用于简单的并发编程,但是对于实际高并发应用还需要优化,如对线程池的优化,还有中断的处理等。

参考

《Effective Java》第二版第十章第69条:并发工具优先于wait和notify

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 微信小程序 ES6Promise.all批量上传文件实现代码

    微信小程序 ES6Promise.all批量上传文件实现代码 客户端 Page({ onLoad: function() { wx.chooseImage({ count: 9, success: function({ tempFilePaths }) { var promise = Promise.all(tempFilePaths.map((tempFilePath, index) => { return new Promise(function(resolve, reject) { wx.

  • Promise.all中对于reject的处理方法

    昨天写了个小爬虫,用axios.all同时请求多个页面时,国内网络的原因很容易就超时然后reject了,佛系resolve不可取啊,然后想到可以实现一个"重发失败请求"的功能. Promise.all(requestPromises).then(...).catch(...) 会在所有requestPromises都resolve时才会进then方法,并且把所有结果以一个数组返回.只要有一个失败,就会进catch.如果在单个请求中定义了catch方法,那么就不会进Promise.all

  • 利用ES6的Promise.all实现至少请求多长时间的实例

    1.背景 我们都知道ajax请求可以加个timeout,就是最多请求多少时间,如果超过这个时间直接就报错. 这个是最多请求多长时间,我现在要做的是,最少要请求多长时间,然后才能执行后续的逻辑. 比如,一个ajax请求 x 毫秒就执行完毕了,但我要让他至少执行1秒钟,那我们会这么想: ajax完成后 , 1. 如果x<1s, 那我们先setTimeout => 1s - x ,然后执行后续操作. 2 如果x>=1s, 那我们直接执行后续操作. 想想这可繁琐了,我们还要在前面记录一下开始时间

  • Java实现Promise.all()的示例代码

    JavaScript的Promise.all() Promise是JavaScript异步编程的一种解决方案,在ES6中引入. 通过Promise.all()可以实现对一组异步请求的统一处理,等待所有异步执行完成之后调用回调函数. 其实,这种并发执行同步等待的需求在Java并发编程中也很常见,那么,是否可以通过Java也来实现这样一个Promise类呢? 使用Java实现Promise.all() 使用工具 CountDownLatch:Java并发工具包中有CountDownLatch类允许一

  • Java连接postgresql数据库的示例代码

    本文介绍了Java连接postgresql数据库的示例代码,分享给大家,具体如下: 1.下载驱动jar 下载地址:https://jdbc.postgresql.org/download.html 2.导入jar包 新建lib文件夹,将下载的jar驱动包拖到文件夹中. 将jar驱动包添加到Libraries 3.程序代码如下:HelloWorld.java package test; import java.sql.Connection; import java.sql.DriverManage

  • java 生成文字图片的示例代码

    本文主要介绍了java 生成文字图片的示例代码,分享给大家,具体如下: import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO;

  • Java动态规划之编辑距离问题示例代码

    动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移.一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划. 动态规划实际上是一类题目的总称,并不是指某个固定的算法.动态规划的意义就是通过采用递推(或者分而治之)的策略,通过解决大问题的子问题从而解决整体的做法.动态规划的核心思想是巧妙的将问题拆分成多个子问题,通过计算子问题而得到整体问题的解.而子问题又可以拆分成更多的子问题,从而用类似递推迭代的方法解决要求的问题.问题描述: 对于序列S和T,

  • Java的静态类型检查示例代码详解

    关于静态类型检查和动态类型检查的解释: 静态类型检查:基于程序的源代码来验证类型安全的过程: 动态类型检查:在程序运行期间验证类型安全的过程: Java使用静态类型检查在编译期间分析程序,确保没有类型错误.基本的思想是不要让类型错误在运行期间发生. 在各色各样的编程语言中,总共存在着两个类型检查机制:静态类型检查和动态类型检查. 静态类型检查是指通过对应用程序的源码进行分析,在编译期间就保证程序的类型安全. 动态类型检查是在程序的运行过程中,验证程序的类型安全.在Java中,编译期间使用静态类型

  • Java随机生成身份证完整示例代码

    身份证算法实现 1.号码的结构 公民身份号码是特征组合码, 由十七位数字本体码和一位校验码组成. 排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码  三位数字顺序码和一位数字校验码. 2.地址码(前六位数) 表示编码对象常住户口所在县(市.旗.区)的行政区划代码,按GB/T2260的规定执行. 3.出生日期码(第七位至十四位) 表示编码对象出生的年.月.日,按GB/T7408的规定执行,年.月.日代码之间不用分隔符. 4.顺序码(第十五位至十七位) 表示在同一地址码所标识的区域范围内,

  • java实现基因序列比较的示例代码

    设计算法,计算两给定基因序列的相似程度. 人类基因由4种核苷酸,分别用字母ACTG表示.要求编写一个程序,按以下规则比较两个基因序列并确定它们的相似程度.即给出两个基因序列AGTGATG和GTTAG,它们有多相似呢?测量两个基因相似度的一种方法称为对齐.使用对齐方法可以在基因的适当位置加入空格,让两个基因的长度相等,然后根据基因的分值矩阵计算分数. 看了很多代码基本上都是用c++或者c写的,但是习惯性写java就用java实现一下 基本的思路就是,和背包问题差不多,实现还是模仿填表的形式去实现的

  • 用java实现跳动的小球示例代码

    实现效果为一个小球接触左右侧时,会反向的运动. import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.paint.Colo

  • 在Java中操作Zookeeper的示例代码详解

    依赖 <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.6.0</version> </dependency> 连接到zkServer //连接字符串,zkServer的ip.port,如果是集群逗号分隔 String connectStr = "192.

  • Java 静态数据初始化的示例代码

    无论创建多少个对象,静态数据都只占用一份存储区域.static关键字不能应用于局部变量,因此它只能作用于域.如果一个域是静态的基本类型域,且也没有对它进行初始化,那么它就会获得基本类型的标准初始值:如果它是一个对象引用,那么它的默认初始值就是null class Bowl { public Bowl(int marker) { System.out.println("Bowl(" + marker + ")"); } void f1(int marker) { Sy

随机推荐