首页 > 编程语言 >Java多线程之ExecutorCompletionService

Java多线程之ExecutorCompletionService

时间:2023-03-23 19:55:51浏览次数:65  
标签:多线程 Java 任务 线程 println 执行 out ExecutorCompletionService

目录

1 ExecutorCompletionService

1.1 简介

当我们向Executor提交一组任务,并且希望任务在完成后获得结果,此时可以考虑使用ExecutorCompletionService

ExecutorCompletionService实现了CompletionService接口。ExecutorCompletionServiceExecutorBlockingQueue功能融合在一起,使用它可以提交我们的Callable任务。这个任务委托给Executor执行,可以使用ExecutorCompletionService对象的takepoll方法获取结果。

ExecutorCompletionService的设计目的在于提供一个可获取线程池执行结果的功能,这个类采用了装饰器模式,需要用户提供一个自定义的线程池,在ExecutorCompletionService内部持有该线程池进行线程执行,在原有的线程池功能基础上装饰额外的功能。

ExecutorCompletionService 相比之前 Future 相比 ,提供了一个通知机制,将结果统一到一个队列,当前提交任务不会阻塞获取,从另一个队列中阻塞获取。

1.2 原理

在这里插入图片描述

执行原理:

  • 在使用ExecutorCompletionService时需要提供一个自定义的线程池Executor,构造ExecutorCompletionService。同时,也可以指定一个自定义的队列作为线程执行结果的容器,当线程执行完成时,通过重写FutureTask#done()将结果压入队列中。
  • 当用户把所有的任务都提交了以后,可通过ExecutorCompletionService#poll方法来弹出已完成的结果,这样做的好处是可以节省获取完成结果的时间。

1.3 Demo示例

1.3.1 未使用ExecutorCompletionService

public class ExecutorCompletionServiceDemo {

   public static void main(String[] args) {

       //这里只是为了方便,真正项目中不要这样创建线程池
       ExecutorService executorService = Executors.newFixedThreadPool(5);
   
       List<Future<String>> list = new ArrayList<>();

       Future<String> future1 = executorService.submit(() -> {
           System.out.println("执行任务1开始");
           try {
               TimeUnit.SECONDS.sleep(5);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println("执行任务1结束");
           return "任务1执行成功";
       });
       list.add(future1);

       Future<String> future2 = executorService.submit(() -> {
           System.out.println("执行任务2开始");
           try {
               TimeUnit.SECONDS.sleep(3);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println("执行任务2结束");
           return "任务2执行成功";
       });
       list.add(future2);


       Future<String> future3 = executorService.submit(() -> {
           System.out.println("执行任务3开始");
           try {
               TimeUnit.SECONDS.sleep(1);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println("执行任务3结束");
           return "任务3执行成功";
       });
       list.add(future3);

       for (int i = 0; i < list.size(); i++) {
           String s = null;
           try {
               s = list.get(i).get();
           } catch (InterruptedException e) {
               e.printStackTrace();
           } catch (ExecutionException e) {
               e.printStackTrace();
           }
           System.out.println(s);
       }
       executorService.shutdown();
   }
}

在这里插入图片描述

我们可以看到三个任务的执行结果会按照提交顺序的任务执行时间进行堵塞依次获取结果;我们提交到线程池中,通过Futrue类的get()方法,会造成堵塞,需要先等执行任务1的线程结束返回结果,才会进行获取下一个任务的执行的结果,那边后面的任务先于任务一执行结束;当然如果工作中我们不需要获取多个任务执行的结果,我们可以采用上面的实现方式去进行并行处理任务;

1.3.2 使用ExecutorCompletionService

如果我们要获取到并行处理任务的结果快慢来进行一些处理,我们就可以使用到ExecutorCompletionService来进行实现;我们来使用ExecutorCompletionService类将线程池进行包装处理下,然后进行提交任务;

public class ExecutorCompletionServiceDemo {

    public static void main(String[] args) {

        //这里只是为了方便,真正项目中不要这样创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        ExecutorCompletionService<String> completionService = new ExecutorCompletionService<>(executorService);

        completionService.submit(() -> {
            System.out.println("执行任务1开始");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("执行任务1结束");
            return "任务1执行成功";
        });

        completionService.submit(() -> {
            System.out.println("执行任务2开始");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("执行任务2结束");
            return "任务2执行成功";
        });

        completionService.submit(() -> {
            System.out.println("执行任务3开始");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("执行任务3结束");
            return "任务3执行成功";
        });

        for (int i = 0; i < 3; i++) {
            try {
                String result = completionService.take().get();
                System.out.println(result);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        executorService.shutdown();
    }
}

在这里插入图片描述

1.4 深入分析说明

解决批量提交任务办法就是使用使用 ExecutorCompletionService,异步通知返回。

1.4.1 所有方法

当前类提供的方法
在这里插入图片描述

1.4.2 构造方法

提供的两个构造函数,一个可以指定返回阻塞队列,另一个使用默认的。另外都需要提供一个线程池进来
在这里插入图片描述

1.4.3 获取方法

提供了三个获取方法,可以看到都是从队列中获取
在这里插入图片描述

take获取:谁先执行完 谁先出来 take() 获取时候回阻塞 也可以通过Poll方法获取
polltake 区别在于 poll 可以执行超时时间,可以看到,谁先执行结束 谁先出来。

1.4.4 提交方法

两个提交任务方法
在这里插入图片描述
如何执行任务结果放入队列呢?

可以看到是将 执行结果放入队列中。
内部实现了异步执行接口,以及重写了它的done方法
在这里插入图片描述

标签:多线程,Java,任务,线程,println,执行,out,ExecutorCompletionService
From: https://www.cnblogs.com/jingzh/p/17248673.html

相关文章

  • java 类似datatable_java jdbc 得到像C#里的datatable一样的表格
    java类似datatable_javajdbc得到像C#里的datatable一样的表格https://blog.csdn.net/weixin_34079140/article/details/114602857publicArrayList>getDataTale2(S......
  • 【Java】关于Queue的用法总结
    【Java】关于Queue的用法总结原文链接:https://blog.csdn.net/qq_25353433/article/details/88016369之前对Queue只有一知半解,常用它的某几个方法,却不知道其中的区别,看了......
  • 关于java的快速输入的一点小bug
    在java打算法题的时候,Scanner类、Sout的速度太慢,所以要用PrintWriter和BufferReader&StreamTokenizer类来进行快速输入。代码如下:importjava.io.*;publicclassMain......
  • 学习记录-JAVA正则表达式
    正则表达式java匹配方法s.matches("JAVA");s.equals("JAVA");来询问该字符串是否匹配表达式正则表达式语法整行字符加上/表示为正则表达式/123/以下所有均省略//......
  • JAVA正则表达式
    JAVA正则表达式参考Java正则表达式|菜鸟教程(runoob.com)1.正则表达式是什么正则表达式(RegularExpression)是一种文本模式,包括普通字符和特殊字符。正则表达式......
  • Java循环
    Java循环Java中有三种主要循环结构:while循环do...while循环for循环while循环while循环结构为:1while(布尔表达式){2//循环内容3}只要布尔表达式为true......
  • java中<<,>>和>>>的含义
    <<表示左移运算符例如8<<2,表示将8向左移2位,结果为32。低位补0。二进制演算:8的二进制:1000向左移动两位结果为100000,换算成十进制即为32,也可以简单的理解为,左移就......
  • javaweb-vue快速入门
    资料来源于:B站尚硅谷JavaWeb教程(全新技术栈,全程实战),本人才疏学浅,记录笔记以供日后回顾视频链接知识点Vue前置条件:需要在项目中放入vue.js文件1){{}......
  • java 原生项目 使用 log4j 写日志 及 log4j.properties 配置说明
    今天遇到一个java原生项目要使用log4j写日志(非maven),写下来供大家参考下载log4j包Apachelog4j1.2-DownloadApachelog4j1.2 把这个文件放到 项目的......
  • java虚拟机(JVM)一
    一、什么是JVM?JVM是一种规范,虚构的计算机(冯诺依曼计算机结构)。跨语言的平台。也就是编译后是二、JVM要学什么?源码到类文件类文件到JVMJVM中各种处理(内部结构、执行方式......