java 多线程 submit future.get方法阻塞问题的解决,实现按照任务完成的先后顺序获取任务的结果

2023-05-16

1、Future

Future模式是多线程设计常用的一种设计模式。Future模式可以理解成:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时间之后,我就便可以从Future那儿取出结果。

Future提供了三种功能:

  • 判断任务是否完成
  • 能够中断任务
  • 能够获取任务执行的结果
    向线程池中提交任务的submit方法不是阻塞方法,而Future.get方法是一个阻塞方法,当submit提交多个任务时,只有所有任务都完成后,才能使用get按照任务的提交顺序得到返回结果,所以一般需要使用future.isDone先判断任务是否全部执行完成,完成后再使用future.get得到结果。(也可以用get (long timeout, TimeUnit unit)方法可以设置超时时间,防止无限时间的等待)
    三段式的编程:1.启动多线程任务2.处理其他事3.收集多线程任务结果,Future虽然可以实现获取异步执行结果的需求,但是它没有提供通知的机制,要么使用阻塞,在future.get()的地方等待future返回的结果,这时又变成同步操作;要么使用isDone()轮询地判断Future是否完成,这样会耗费CPU的资源。
    解决方法:CompletionService和CompletableFuture(按照任务完成的先后顺序获取任务的结果)

2、CompletionService是java1.8之前最好用的方法

能够实现按照任务完成的先后顺序获取任务的结果。

public class TestCompletionService {
	private static final String commandstr01 = "hahah";
	private static final String commandstr02 = "hahah";
	
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//1、创建一个线程池
		ExecutorService executorService = Executors.newCachedThreadPool();
		
		CompletionService<String> completionService = new ExecutorCompletionService<String>(executorService);
		
		completionService.submit(new MyThreadt33(commandstr01));
		completionService.submit(new MyThreadt44(commandstr01));
			
		executorService.shutdown();
		
		System.out.println(completionService.take().get());
		System.out.println(completionService.take().get());
	}
}
 
class MyThreadt33 implements Callable<String>{
	private String commandstr;          // 要运行的mingling
	public MyThreadt33(String commandstr) {
		this.commandstr = commandstr;
	}
	@Override
	public String call() throws Exception {
		int sum = 0;
		for (int i = 0; i < 100; i++) {
			Thread.sleep(200);
			sum += i;
			System.out.println("Mythread3: "+i);
		}
		return String.valueOf(sum+300000);
	}
}
 
class MyThreadt44 implements Callable<String>{
	private String commandstr;          // 要运行的mingling
	public MyThreadt44(String commandstr) {
		this.commandstr = commandstr;
	}
	@Override
	public String call() throws Exception {
		int sum = 0;
		for (int i = 0; i < 50; i++) {
			Thread.sleep(200);
			sum += i;
			System.out.println("Mythread4: "+i);
		}
		return String.valueOf(sum+400000);
	}
}

CompletionService方法可以通过completionService.take().get()方法获取最快完成的线程的返回结果(若当前没有线程执行完成则阻塞直到最快的线程执行结束),第二次调用则返回第二快完成的线程的返回结果。

3、CompletableFuture接口

所谓异步调用其实就是实现一个可无需等待被调函数的返回值而让操作继续运行的方法。简单的讲就是另启一个线程来完成调用中的部分计算,使调用继续运行或返回,而不需要等待计算结果。但调用者仍需要取线程的计算结果。

JDK1.5新增了Future接口,用于描述一个异步计算的结果。虽然 Future 以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。

JDK1.8后提出了CompletableFuture接口实现了Future和CompletionStage两个接口,CompletionStage可以看做是一个异步任务执行过程的抽象(CompletionStage代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段,一个阶段的计算执行可以是一个Function,Consumer或者Runnable。比如:

stage.thenApply(x -> square(x)).thenAccept(x -> System.out.print(x)).thenRun(() -> System.out.println())

我们可以基于CompletableFuture创建任务和链式处理多个任务,并实现按照任务完成的先后顺序获取任务的结果。

(1)创建任务

##使用runAsync方法新建一个线程来运行Runnable对象(无返回值);

##使用supplyAysnc方法新建线程来运行Supplier对象(有返回值);

##基于线程池创建

(2)任务的异步处理

不论Future.get()方法还是CompletableFuture.get()方法都是阻塞的,为了获取任务的结果同时不阻塞当前线程的执行,我们可以使用CompletionStage提供的方法结合callback来实现任务的异步处理。

  • whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。

  • whenCompleteAsync:把 whenCompleteAsync 这个任务继续提交给线程池来进行执行,也就是并行执行。

  • thenApply:当一个线程依赖另一个线程时,可以使用 thenApply 方法来把这两个线程串行化

  • thenAccept:thenAccept接收上一阶段的输出作为本阶段的输入,并消费处理,无返回结果。

  • thenRun:不关心前一阶段的计算结果,因为它不需要输入参数,进行消费处理,无返回结果。

  • thenCombine:会把两个 CompletionStage 的任务都执行完成后,把两个任务的结果一块交给 thenCombine 来处理。

  • applyToEither :两个CompletionStage,谁执行返回的结果快,我就用那个CompletionStage的结果进行下一步的转化操作。

  • acceptEither 方法:两个CompletionStage,谁执行返回的结果快,我就用那个CompletionStage的结果进行下一步的消耗操作

public class TestCompletableFuture {
	private static final String commandstr01 = "hahah";
	private static final String commandstr02 = "hahah";
	private static final String commandstr03 = "hahah";
	private static final String commandstr04 = "hahah";
 
	    public static void main(String[] args) throws InterruptedException, ExecutionException{
	        
	    	ExecutorService executorService = Executors.newCachedThreadPool();
	    	
	        CompletableFuture.supplyAsync(new MyThreadt444(commandstr02),executorService).whenComplete((result, e) -> {
	        	//执行线程执行完以后的操作。
	            System.out.println(result + " " + e);
	        }).exceptionally((e) -> {
	            //抛出异常
	        	System.out.println("exception " + e);
	            return "exception";
	        });
	        
	         CompletableFuture.supplyAsync(new MyThreadt333(commandstr02),executorService).whenComplete((result, e) -> {
	        	//执行线程执行完以后的操作。
	        	System.out.println(result + " " + e);
	        }).exceptionally((e) -> {
	            System.out.println("exception " + e);
	            return "exception";
	        });
	    }
}
 
 
 
class MyThreadt333 implements Supplier<String>{
 
	private String commandstr;          // 要运行的mingling
	public MyThreadt333(String commandstr) {
		this.commandstr = commandstr;
	}
	@Override
	public String get() {
		int sum = 0;
		for (int i = 0; i < 30; i++) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			sum += i;
			System.out.println("Mythread333: "+i);
		}
		return String.valueOf(sum+300000);
	}
}
 
class MyThreadt444 implements Supplier<String>{
 
	private String commandstr;          // 要运行的mingling
	public MyThreadt444(String commandstr) {
		this.commandstr = commandstr;
	}
	@Override
	public String get() {
		int sum = 0;
		for (int i = 0; i < 40; i++) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			sum += i;
			System.out.println("Mythread444: "+i);
		}
		return String.valueOf(sum+400000);
	}
}

在CompletableFuture接口中除了使用whenComplete还可以使用handle等方法能实现按照任务完成的先后顺序获取任务的结果。

4、几种多线程并发取结果方式的总结

下图参考自:https://blog.csdn.net/u011726984/article/details/79320004
在这里插入图片描述
原文地址:https://blog.csdn.net/qq_34562093/article/details/90209520

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java 多线程 submit future.get方法阻塞问题的解决,实现按照任务完成的先后顺序获取任务的结果 的相关文章

  • 记一次 Native Crash Abort message:‘FORTIPY :vsprintf:prevented 33-byte write into 32-byte buffer ’

    先贴上关键日志 第一眼看到日志 xff0c 以为是缺少了Arm64 的so文件 xff0c 查看后发现并没缺少 xff1b 无奈之下 xff0c 只有复现这个Crash xff0c 一点点缩小排查范围 xff1b 最终将问题的矛头指向了项目
  • spring Bean的完整生命周期

    spring bean的完整生命周期 1 1 容器启动时 BeanFactoryPostProcessor gt postProcessBeanFactory Spring IoC容器允许BeanFactoryPostProcessor在容
  • 1秒学会 Vim 插件管理

    Vim pathogen 通常情况下安装vim插件 xff0c 通常是将所有的插件和相关的doc文件都安装在中一文件夹中 xff0c 如将插件全部安装在 usr share vim vim73 plugin 目录下 xff0c 将帮助文档全
  • 【树莓派4B】Manjaro-ARM系统下配置VNC以及遇到的问题

    在两三个小时内经历了各种尝试之后 xff0c 终于成功 xff0c 现在记录一下过程 xff0c 以免下次忘记 系统 xff1a 我实在树莓派4B 8G版上安装了Manjaro 1 下载 wget https github com azal
  • 【硬件调试】串口乱码原因汇总

    一般有以下几种原因 xff0c 列举一下提醒自己 1 波特率出错或者其他串口设置出错 2 三线即可进行通信 xff0c 未接地或者接触不良 xff0c TTL 232 TX RX接反 xff0c 485 A B接反 3 如果接电脑可以通信
  • 真实面试题-高并发如何设置JVM参数

    阿里终面 xff1a 每天100w次登陆请求 xff0c 8G内存该如何设置JVM参数 设置内存大小 由于服务器只有8G内存 xff0c 需要合理分配内存给JVM xff0c 避免过度分配导致内存不足 xff0c 也避免分配不足导致频繁的垃
  • 项目切换分支后突然kotlin not configured

    从其他分支切换回来新功能开发分支后提示kotlin not configured 搜索网上提示是版本问题 要将jre8去掉 如 implementation 39 org jetbrains kotlin kotlin stdlib jre
  • 从安卓系统USB升级包里提取system.img、boot.img和recovery.img在内的镜像文件

    1 前言 如果你拿到一个USB升级包 xff0c 你会发现升级包的结构基本相似 但是里面并不是直接就有包括system img boot img和recovery img在内的镜像文件 如果我们需要在Android手机上获取Magisk 提
  • 使用PE微盘制作启动U盘变成两个盘符后,恢复原始状态

    在利用好系统U盘启动制作了U盘启动盘后 xff0c 我们就可以重装系统了 重装系统后 xff0c 有些朋友想要将U盘启动盘复原成普通U盘 xff0c 但发现仅仅靠格式化还不能完全释放空间 xff0c 这该怎么办呢 xff1f 别着急 xff
  • Idea搭建第一个Vue脚手架项目和遇到的问题

    官方教程传送门 新旧版的命令和项目结构不太一样 xff0c 具体可以看上面的官方文档 配置环境 见https blog csdn net qq 33189961 article details 106970036 在IDEA新建static
  • docker部署nodejs项目

    本文主要分享使用docker部署nodejs项目 使用docker部署项目主要分为三步 1 创建nodejs项目 编写package json为项目安装依赖所用 34 name 34 34 expressPro 34 34 version
  • Android 开发跨进程大图

    对于跨进程传输数据的问题 xff0c 我之前也写了一篇 xff0c 配合阅读效果更好 xff1a Android 开发太难了 xff0c 这异常竟然捕获不到 xff1f 1 抛一个问题 这一天 xff0c 法海想锻炼小青的定力 xff0c
  • linux修改键位:ctrl与caps调换

    ctrl比caps的使用频率更高 xff0c 但是ctrl的位置却对小拇指并不友好 有时使用gnome tweak tool设置键位并没有生效 下面介绍两个简单的方法修改键位 1 使用xmodmap修改键位 我们可以使用包管理器轻松安装xm
  • pandas无法打开.xlsx文件,xlrd.biffh.XLRDError: Excel xlsx file; not supported

    原因是最近xlrd更新后只支持 xls文件 所以pandas read excel xxx xlsx 会报错 可以安装旧版xlrd xff0c 在终端中运行 xff1a pip3 uninstall xlrd pip3 install xl
  • python&多路归并

    问题 xff1a 在项目中 xff0c 需从待分析的数据中选出最大的前几名 xff0c 但由于数据量太大 xff0c 直接排序会内存报错 xff0c 因此尝试用多路归并的思路来解决问题 接口 xff1a 一个目录下有x个已排序好的csv 最
  • 03_spring的基本配置

    bean元素的id和name属性 在Spring配置中 xff0c id和name属性都可以表示bean元素的名称 xff0c 不同的是 xff1a id属性 xff0c 遵守XML语法ID约束 必须以字母开始 xff0c 可以使用字母 数
  • Linux服务器的登录与使用

    Linux服务器的登录与使用 关于登录Linux服务器的方式有很多种 xff0c 本文重点介绍了Linux和Windows下的登录和使用Linux服务器的方式 Linux服务器 服务器可看为是一台功能配置强大的电脑 xff0c 有独立的操作
  • Angular2 - [innerHTML] && pipe(把字符串里的 /n 替换成 <br/>)

    需求 把接口返回的使用说明字符串innerHTML出来 xff1b 本来想直接 innerHTML 就可以了 xff0c 但是事不遂人愿 xff0c 那就写个pipe过滤一下 xff1b 过程 接口返回字符串 xff1a 34 coupon
  • vscode ftp-sync 插件使用

    插件安装和配置 1 下载ftp sync插件 extensions中直接搜索安装即可 2 ctrl 43 shift 43 p 选择执行Ftp sync init 配置文件json含义如下 span class token punctuat
  • Ubuntu16.04终端执行`sudo apt-get update`遇到appstream问题

    Ubuntu 16 04 终端执行sudo apt get update遇到问题 E xff1a Problem executing scripts APT Update Post Invoke Success br 39 if usr b

随机推荐

  • Cloudflare5s盾破解|爬虫自动验证|解决方案

    一 什么是Cloudflare5s盾 Cloudflare是一个网站加速和安全服务提供商 Cloudflare 5s盾是指网站防御模式 xff0c 它可以防止恶意流量和攻击 xff0c 如DDoS SQL注入 XSS等 xff0c 保护网站
  • 若依Vue入门——服务器部署篇

    目录 前端 xff0c ruoyi ui 编译 部署 后端 xff0c ruoyi 使用若依前后端分离的Vue 43 Springboot脚手架 xff0c 进行编译与在Windows Server服务器上的部署 使用IDEA作为IDE 使
  • Spring启动流程解析(总)

    一 xff0c Spring启动流程概述 Spring的IoC容器在实现控制反转和依赖注入的过程中 xff0c 可以划分为两个阶段 xff1a 容器启动阶段 Bean实例化阶段 容器初始化 加载配置 分析配置信息 将Bean信息装配到Bea
  • Node,docker 中安装node.js

    1 启动docker服务 首先启动docker服务 systemctl start docker 2 获取node最新镜像 启动完成之后拉取node最新镜像 xff1a docker pull node 然后开始等待 xff0c 最后拉取完
  • 慎用!!! rm -rf 潜藏着巨大的危险!

    平时删除文件爱偷个懒 笔直 rm rf 过去就不想事了 今天碰到一个很意外的情况 以前也有碰到过 但总没留意到 在这里记下提醒自己 希望大家也多留个神 先说说 rm 的用法 官方的描述是这样的 rm 命令可以删除一个目录中的一个或多个文件或
  • 个人面试细节、技巧总结(没有面试题哦!)

    面试除了自身技能过硬外 xff0c 良好的沟通 xff0c 平和的心态 xff0c 细节的拿捏也都是额外的加分项 最后 xff0c 以些许运气加以点缀 xff0c offer 便八九不离十了 参加工作两年有余 xff0c 只大专文凭 xff
  • EFCore 实现连接MySQL并创建实体类

    EFCore 实现连接MySQL并创建实体类 所需文件版本 1 Pomelo EntityFrameworkCore MySql 2 2 0 2 Microsoft EntityFrameworkCore Tools 2 2 0 3 Pom
  • Win10设置文件夹背景色

    右键个性化 选择左侧的颜色 xff0c 根据自己的喜欢进行设置
  • 快速计算代码行小工具

    非常方便用于统计代码行的小工具叫line counter xff0c 使用以下命令获取工具 pip install line counter 使用 34 line 34 命令可以获取当前目录下的文件与行数统计 xff0c 效果如下 line
  • 协议栈设计_LwIP笔记

    文章目录 LWIP主进程工作链路层LWIP数据包收发函数框架ARP 地址解析协议 表ARP表查询IP层ICMP处理 Internet 控制报文协议 TCPIP Thread线程启动流程 tcpip thread主线程处理 LWIP主进程工作
  • VirtualBox虚拟机串口调试方法

    1 windows下调试virtualbox的虚拟机串口 2 Cannot open dev ttyS0 Permission denied解决 出现了Cannot open dev ttyS0 Permission denied提示字样
  • 基于STC89C51和L298N的42步进电机控制

    步进电机是将电脉冲信号转变为角位移或线位移的开环控制元件 电机的转速 停止的位置只取决于脉冲信号的频率和脉冲数 xff0c 而不受负载变化的影响 xff0c 即给电机加一个脉冲信号 xff0c 电机则转过一个步距角 步进电机必须由双环形脉冲
  • python实现一个QQ群聊天机器人

    最近由于项目需求 xff0c 需要做个QQ群的聊天机器人用于回答咨询的问题 在这样的情况下 xff0c 我开始了QQ机器人的踩坑之旅 这个机器人需求就是在群里有人 64 机器人 43 问题时 xff0c 机器人通过检测信息是否有 64 之后
  • 使用python控制打印机

    Python安装win32api模块 xff1a pip install pypiwin32 一组扩展模块 xff0c 提供对许多Windows API函数的访问 http sourceforge net projects pywin32
  • python静默打印pdf

    span class token keyword import span win32api span class token keyword import span win32print span class token keyword d
  • 超简单!!小白级 PXE 实现无人值守批量安装教程

    author Tresser date 2017 4 9 03 50 此文较长 请细心看完 一定可以成功 实验环境 主机 CentOS 6 5 x86 虚拟机 准备工作 1 本地 yum 仓库 2 DHCP 服务器 3 TFTP 服务器 4
  • python 提示错误AttributeError: type object 'str' has no attribute '_name_'

    在做 Machine Learning in Action 书中的第三章绘制树形图时遇到了这个问题AttributeError type object 39 str 39 has no attribute 39 name 39 很明显是if
  • C++ IPC进程间的通信《C++多线程编程实战》

    临界值 xff1a 程序中能被访问共享内存的部分 2个CPP文件需要在同一个解决方案中分别创建2个项目 进程间通信示例 xff1a 程序一开始就有2个进程 xff0c 它们在一个普通窗口中完成绘制矩形的任务 2个进程相互通信 xff0c 一
  • C# 使用Newtonsoft.Json读写Json文件

    原文地址 xff1a https www cnblogs com LicwStack p 9522345 html 0 json文件 34 CAN 34 false 34 AccCode 34 4294901856 34 Id 34 768
  • java 多线程 submit future.get方法阻塞问题的解决,实现按照任务完成的先后顺序获取任务的结果

    1 Future Future模式是多线程设计常用的一种设计模式 Future模式可以理解成 xff1a 我有一个任务 xff0c 提交给了Future xff0c Future替我完成这个任务 期间我自己可以去做任何想做的事情 一段时间之