IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 多线程Future模式使用 -> 正文阅读

[Java知识库]多线程Future模式使用

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


一、使用场景

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

二、关于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 {

  @Resource
  private 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
  @Override
  public 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
  @Override
  public 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抛出的异常。

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

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-22 20:22:50  更:2022-03-22 20:26:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:46:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码