上次分享了多线程与自动任务的风花雪月悲惨结局,今天借此继续分享下多线程带返回结果的基本讨论与实现。


一、使用场景

一个业务方法可能执行时间很长,而我们也不急着摇返回结果,那么就可以用多线程去开启一个子线程执行这个业务方法,同时,子线程可以返回这个业务方法的返回结果,那这是什么模式呢?

二、关于Future

1.什么是Future模式

Future模式
是多线程开发中非常常见的一种设计模式。它的核心思想是异步调用。当我们需要调用一个函数方法时。如果这个函数执行很慢,那么我们就要进行等待。但有时候,我们可能并不急着要结果。因此,我们可以让被调用者立即返回,让他在后台慢慢处理这个请求。对于调用者来说,则可以先处理一些其他任务,在真正需要数据的场合再去尝试获取需要的数据。

场景比如:外卖。
比如在午休之前我们可以提前叫外卖,只需要点好食物,下个单。然后我们可以继续工作。到了中午下班的时候外卖也就到了,然后就可以吃个午餐,再美滋滋的睡个午觉。而如果你在下班的时候才叫外卖,那就只能坐在那里干等着外卖小哥,最后拿到外卖吃完午饭,午休时间也差不多结束了。

使用Future模式
获取数据的时候无法立即得到需要的数据。而是先拿到一个契约,你可以再将来需要的时候再用这个契约去获取需要的数据,这个契约就好比叫外卖的例子里的外卖订单。

2.与用普通方式的差别

下面用一张图对比下:

三、代码简单实现

自动任务入口


import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.xiaotian.datadiver.core.Result;
import com.xiaotian.datadiver.service.ThreadService;
import com.xiaotian.datadiver.util.LicenseUtil;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;/*** 业务自动任务** @author zhengwen**/
@Configuration
@EnableScheduling
@ConditionalOnProperty(prefix = "scheduling", name = "enabled", havingValue = "true")
@Slf4j
public class BusinessTask {@Resourceprivate ThreadService threadService;/*** 多线程-主从线程与周期测试*/@Scheduled(fixedDelayString = "${scheduling.business.masterSlaveRun.fixedDelay}")public void masterSlaveThreadRunTest() {log.info("--多线程-主从线程与周期测试--");String now = DateUtil.now();//执行完成后间隔3秒,设置睡5秒钟,设置睡5秒钟long sleepTime = 5000;//threadService.slaveThreadRun(now, sleepTime);try {Future<?> ft = threadService.slaveThreadRunFuture(now,sleepTime);//主线程继续干其他事情threadService.slaveThreadRun(now,sleepTime);//拿带返回Future结果的线程里的返回数据,这里get到的就是业务方法里返回的对象,与同步调用返回的对象一样样的Result<?> res = (Result<?>) ft.get();log.info("子线程返回Future:{}", JSONUtil.toJsonStr(res));} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}log.info("--主线程运行完成,时间:{}", now);}
}

threadService实现类


import com.xiaotian.datadiver.core.Result;
import com.xiaotian.datadiver.core.ResultGenerator;
import com.xiaotian.datadiver.service.ThreadService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;/*** @author zhengwen**/
@Slf4j
@Service
public class ThreadServiceImpl implements ThreadService {@Async@Overridepublic void slaveThreadRun(String now, long sleepTime) {//主线程是1分钟执行一次,这里我就让睡1分半钟try {Thread.sleep(sleepTime);} catch (InterruptedException e) {log.error("----从线程异常:{}", e.getMessage(), e);}log.info("线程[{}]我{}睡了{},醒了,可以继续了", Thread.currentThread().getName(), now, sleepTime);}@Async@Overridepublic Future<?> slaveThreadRunFuture(String now, long sleepTime) {ExecutorService es = Executors.newSingleThreadExecutor();Future ft = es.submit(() -> {//业务方法返回Result对象Result<?> rs = slaveThreadRunHasResult(now, sleepTime);return rs;});return ft;}private Result<?> slaveThreadRunHasResult(String now, long sleepTime) {//主线程是1分钟执行一次,这里我就让睡1分半钟try {Thread.sleep(sleepTime);} catch (InterruptedException e) {log.error("----从线程异常:{}", e.getMessage(), e);}log.info("子线程[{}]我{}睡了{},醒了,可以继续了", Thread.currentThread().getName(), now, sleepTime);return ResultGenerator.genSuccessResult("子线程[" + now + "]运行时长[" + sleepTime + "]后返回");}
}

代码就是这么简单,没啥好解释的,唯一就是这里用自动任务套了一层,然后主线程调用子线程方法,子线程又开启线程执行业务方法而已。在实际使用过程中,可以根据这个进行剪裁。


四、执行结果截图



主从线程打印日志,做了标记,结合自动任务入口调用顺序,自行体会下。

总结

1、Future模式思路棒棒哒
2、不得不说java的多线程操作越来越简单了
3、这里的Future是使用的Runnable,其实也可以使用Callable实现
4、需要顺便了解下ExecutorService.execute()和ExecutorService.submit()的区别(为什么这里是调用的Executor.submit())
PS:
1、接收的参数不一样
2、submit有返回值,而execute没有
原话:
Method submit extends base method Executor.execute by creating and returning a Future that can be used to cancel execution and/or wait for completion.
翻译的意思:
用到返回值的例子,比如说我有很多个做validation的task,我希望所有的task执行完,然后每个task告诉我它的执行结果,是成功还是失败,如果是失败,原因是什么。然后我就可以把所有失败的原因综合起来发给调用者。不过我觉得cancel execution这个用处不大,很少有需要去取消执行的,看多个线程有一个已经出现事务问题了,会不会有这样的使用需求。

3、submit方便Exception处理
原话:
There is a difference when looking at exception handling. If your tasks throws an exception and if it was submitted with execute this exception will go to the uncaught exception handler (when you don’t have provided one explicitly, the default one will just print the stack trace to System.err). If you submitted the task with submit any thrown exception, checked or not, is then part of the task’s return status. For a task that was submitted with submit and that terminates with an exception, the Future.get will rethrow this exception, wrapped in an ExecutionException.
翻译的意思:
如果你在你的task里会抛出checked或者unchecked exception,而你又希望外面的调用者能够感知这些exception并做出及时的处理,那么就需要用到submit,通过捕获Future.get抛出的异常。

最后就到这里了,希望能帮到大家。

多线程Future模式使用相关推荐

  1. java多线程 future_Java多线程Future模式

    package future; import java.util.Date; /** * 服务器 * * @author wpy * */ public class Service { /** * 1 ...

  2. Java多线程编程中Future模式的详解

    转载自 https://www.cnblogs.com/winkey4986/p/6203225.html Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker ...

  3. 多线程设计模式 - Future模式

    Future模式是多线程开发中非常常见的一种设计模式,它的核心思想是异步调用.这类似我们日常生活中的在线购物流程,带在购物网看着一件商品时可以提交表单,当订单完成后就可以在家里等待商品送货上门.或者说 ...

  4. 学习多线程中的 Future 模式一篇文章就够了 !!!

    文章目录 一.Future 模式 二.Future模式的主要角色 三.Future模式的简单实现 四.JDK中的Future模式 五.Guava对Future模式的支持 一.Future 模式 Fut ...

  5. 多线程基础之设计模式Future模式

    一. Future模式介绍 前面的 Thread-Per-Message 模式将耗时时间的处理交给其他线程, 的确可以提高程序的响应性, 但是在将处理交出去的时候, 处理结果仍是未知的, 而等待处理结 ...

  6. java多线程系列13 设计模式 Future 模式

    Future 模式 类似于ajax请求  页面异步的进行后台请求 用户无需等待请求的结果 就可以继续浏览或者操作 核心就是:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑 ...

  7. 多线程设计模式(二):Future模式

    一.什么是Future模型: 该模型是将异步请求和代理模式联合的模型产物.类似商品订单模型.见下图: 客户端发送一个长时间的请求,服务端不需等待该数据处理完成便立即返回一个伪造的代理数据(相当于商品订 ...

  8. Java是如何实现Future模式的?万字详解!

    1 Future是什么? 先举个例子,我们平时网购买东西,下单后会生成一个订单号,然后商家会根据这个订单号发货,发货后又有一个快递单号,然后快递公司就会根据这个快递单号将网购东西快递给我们.在这一过程 ...

  9. 从理解Future模式到仿写JUC的Future模式

    1.Future模式 过生日,在线上定蛋糕的例子可以形象的解释Future模式. 两个步骤: 1.下单 - 委托制作蛋糕:你在线定下单订蛋糕,将制作蛋糕的工作委托给了蛋糕店. 2.取蛋糕:凭着在线支付 ...

最新文章

  1. 机器学习模型五花八门不知道怎么选?这份指南告诉你
  2. 【hihocoder】三十九周:二分.归并排序之逆序对
  3. vs2019使用sqlite数据库远程连接linux
  4. 每日一题(7) —— 求余运算符
  5. 数据结构之图:无向图的介绍与功能实现,Python——22
  6. java 查询solr_java实现简单的solr查询
  7. oracle中ak约束,Oracle自定义聚集函数
  8. 线程的故事:3 位“母亲”成就了优秀的我!
  9. 使用EasyUI的插件前需要引入的文件
  10. kafka是什么_Kafka凭什么速度那么快?
  11. win10亮度怎么调_装好原版win10后,没有这样设置过,你的系统怎么可能好用!...
  12. Resnet 网络结构的理解以及论文
  13. 教师进修学校计算机教案,信息化教学教案
  14. Matlab是常见的高级语,高级语言具有哪些特点 试述低级语言与高级语言的特点...
  15. 关于EAN13码的设置问题
  16. 微信小程序无法看视频
  17. C++11新特性 - 侯捷
  18. 网站api自己怎么写_短视频文案怎么写?看这4个素材网站就够了
  19. 如何使用C语言播放音乐
  20. android opengl版本太低,安卓模拟器opengl_安卓模拟器无法安装“系统opengl版本过低”的通用解决方法_安卓模拟器通用版_通用安卓模拟器...

热门文章

  1. java开发中常用的Git命令详解
  2. Windows下的chcp命令(更改该控制台的活动控制台代码页)
  3. 程序员应该加入的3个QQ群
  4. 第一篇博客:梦就此开始
  5. python模块安装的几种方法
  6. Flot转身为其它的SPC控制图
  7. 宝莱坞机器人之恋 电影 全部歌曲 铁甲情痴终结者 全部插曲 在线试听 下载
  8. 为什么红黑树查询快_目前最详细的红黑树原理分析(大量图片+过程推导!!!)...
  9. CentOS7 彻底卸载 MySQL5.7 (保姆级)
  10. 重装完的win10卡“请稍等”,然后电脑不断自动重启还是卡在“请稍等”?