创建线程的两种方式

直接继承 Thread

实现 Runnable 接口

这两种方式都有一个缺点:在执行完成任务之后,无法直接获取到最后的执行结果。如果需要获取执行结果,就必须通过共享变量或线程通信的方式来达到想要的效果,较为麻烦。

所以从 Java 1.5 起,就提供了两种方式:Callable 和 Future,通过它们可以在任务执行结束后得到任务执行结果。

Runnable 与 Callable

首先是 java.lang.Rannable,它是一个接口,里面只声明了一个 run() 方法:

@FunctionalInterface

public interface Runnable {

public abstract void run();

}

由于 run() 方法的返回值类型为 void,所以在线程执行完后无任何返回结果。

然后是 java.util.concurrent.Callable,它也是一个接口,也只声明了一个方法,其名为 call():

@FunctionalInterface

public interface Callable {

V call() throws Exception;

}

可以看到,这是一个泛型接口,返回的类型就是传进来的 V 类型。

那么,如何使用 Callable 呢?一般是结合 ExecutorService 来使用。ExecutorService 声明了几种 submit 方法,其中有一个就是传入 Callable:

Future submit(Callable task);

Future

Future 声明了对具体的 Runnable 或者 Callable 任务执行进行取消、查询、结果获取等方法。必要时可以通过 get 方法获取执行结果,该方法会阻塞直到任务返回结果。

public interface Future {

boolean cancel(boolean mayInterruptIfRunning);

boolean isCancelled();

boolean isDone();

V get() throws InterruptedException, ExecutionException;

V get(long timeout, TimeUnit unit)

throws InterruptedException, ExecutionException, TimeoutException;

}

由此可见,Future 提供了三种功能:

取消任务:参数表示是否允许中途取消(中断)

判断状态:是否已取消、是否已完成

获取结果:两种方式,指不指定时间

因为 Future 只是一个接口,所以无法直接用来创建对象,因此有了下面的 FutureTask。

FutureTask

首先看下 FutureTask 的继承关系:

可以看出 RunnableFuture 继承了 Runnable 接口和 Future 接口,而 FutureTask 实现了 RunnableFuture 接口。所以它既可以作为 Runnable 被线程执行,又可以作为 Future 得到 Callable 的返回值。

然后可以看到 FutureTask 内部有这几种状态:

private volatile int state;

private static final int NEW = 0;

private static final int COMPLETING = 1;

private static final int NORMAL = 2;

private static final int EXCEPTIONAL = 3;

private static final int CANCELLED = 4;

private static final int INTERRUPTING = 5;

private static final int INTERRUPTED = 6;

再根据注释,可以得知当创建一个 FutureTask 对象时,初始状态是 NEW,在运行过程中,运行状态仅在方法set,setException 和 cancel 中转换为终端状态。有四种状态转换过程:

NEW -> COMPLETING -> NORMAL:正常执行并返回结果(run 执行成功再设置状态为 COMPLETING)

NEW -> COMPLETING -> EXCEPTIONAL:执行过程中出现异常(setException 先设置状态为 COMPLETING)

NEW -> CANCELLED:执行前被取消

NEW -> INTERRUPTING -> INTERRUPTED:执行时被中断(cancel 参数为 true 才可能出现这个状态)

最后来看下 FutureTask 的两个构造器:

public FutureTask(Callable callable) {

if (callable == null)

throw new NullPointerException();

this.callable = callable;

this.state = NEW; // ensure visibility of callable

}

public FutureTask(Runnable runnable, V result) {

this.callable = Executors.callable(runnable, result);

this.state = NEW; // ensure visibility of callable

}

可知传入的任务最后都是付给内部的 private Callable callable。

事实上,FutureTask 是 Future 接口的一个唯一实现类。

更多关于 FutureTask 的源码分析,可以看 FutureTask源码解析 这篇文章。

使用示例

Future

第一种方式是使用继承了 ExecutorService 的线程池 ThreadPoolExecutor 中的 submit 方法,将 Callable 直接提交创建 Future。

import java.util.concurrent.*;

public class FutureExample {

static class MyCallable implements Callable {

@Override

public String call() throws Exception {

System.out.println("do something in callable");

Thread.sleep(5000);

return "Ok";

}

}

public static void main(String[] args) throws InterruptedException, ExecutionException {

ExecutorService executorService = Executors.newCachedThreadPool();

Future future = executorService.submit(new MyCallable());

System.out.println("do something in main");

Thread.sleep(1000);

String result = future.get();

System.out.println("result: " + result);

}

}

FutureTask

第二种方法是创建一个写好 Callable 的 FutureTask 对象实例,再 submit。因为 FutureTask 内部本身拥有 run 方法,也可以直接创建线程 Thread 运行。

利用 ExecutorService

import java.util.concurrent.*

public class FutureTaskWithExecutorService {

public static void main(String[] args) throws InterruptedException, ExecutionException {

FutureTask futureTask = new FutureTask<>(() -> { // java 8 函数式写法

System.out.println("do something in callable");

Thread.sleep(5000);

return "Ok";

});

ExecutorService executorService = Executors.newCachedThreadPool();

executorService.submit(futureTask);

System.out.println("do something in main");

Thread.sleep(1000);

String result = futureTask.get();

System.out.println("result: " + result);

}

}

利用 Thread

import java.util.concurrent.*

public class FutureTaskWithThread {

public static void main(String[] args) throws InterruptedException, ExecutionException {

FutureTask futureTask = new FutureTask<>(new Callable() {

@Override

public String call() throws Exception {

System.out.println("do something in callable");

Thread.sleep(5000);

return "Ok";

}

});

new Thread(futureTask).start();

System.out.println("do something in main");

Thread.sleep(1000);

String result = futureTask.get();

System.out.println("result: " + result);

}

}

参考资料

futuretask java 并发请求_【Java并发】Runnable、Callable、Future、FutureTask相关推荐

  1. Java并发编程举例Runnable, Callable, Future, FutureTask, CompletionService

    import java.util.concurrent.*;/*** Created by chenh on 2017/3/23.*/ public class ConcurrentDemo {// ...

  2. java currenttimemillis 效率_高并发场景下System.currentTimeMillis()的性能问题的优化

    前言 System.currentTimeMillis()的调用比new一个普通对象要耗时的多(具体耗时高出多少我也不知道,不过听说在100倍左右),然而该方法又是一个常用方法,有时不得不使用,比如生 ...

  3. 高并发编程_高并发编程系列:7大并发容器详解(附面试题和企业编程指南)...

    不知道从什么时候起,在Java编程中,经常听到Java集合类,同步容器.并发容器,高并发编程成为当下程序员需要去了解掌握的技术之一,那么他们有哪些具体分类,以及各自之间的区别和优劣呢? 只有把这些梳理 ...

  4. oracle rac 高并发性能_高并发业务下 JVM 涉及的垃圾回收与性能问题分析与定位...

    最近好多 Java 的朋友问:"高并发业务场景下,JVM涉及的性能问题好难搞呀--".看来是大家的技术经验相对少了些,拿不准该从哪些地方上手,其实,每个技术人要该懂得怎样更好打造自 ...

  5. 高并发解决方案_高并发提交订单的解决方案

    商城系统,根据不同的业务需求,归类出几种购买活动.比如:常规商品的购买,稀缺商品的秒杀活动,特价商品的限时优惠活动,加价换购活动,拼团活动,众筹活动,将要发行销售的预售活动.这里,针对预售活动场景,来 ...

  6. java resources 目录_[Java] 在 jar 文件中读取 resources 目录下的文件

    注意两点: 1. 将资源目录添加到 build path,确保该目录下的文件被拷贝到 jar 文件中. 2. jar 内部的东西,可以当作 stream 来读取,但不应该当作 file 来读取. 例子 ...

  7. php 模拟并发请求_PHP模拟并发请求

    原理:使用curl_init()创建多个请求实例,再使用curl_multi_init()批量执行创建的多个请求实例. 文件1:curl.php<?php $threads=500;//并发请求 ...

  8. java取负数_[Java] 告别“CV 工程师”码出高效!(基础篇)

    作为一名资深的 CV 工程师,某天,当我再一次日常看见满屏的报错信息与键盘上已经磨的泛白的 Ctrl.C.V 这三个按键时,我顿悟了. 百度谷歌复制粘贴虽然很香,但是总是依靠前人种树,终会有一天失去乘 ...

  9. mysql 高并发 响应时间_高并发,你真的了解吗?

    摘要:本文介绍高并发系统的度量指标,讲述高并发系统的设计思路,再梳理高并发的关键技术,最后结合作者的经验做一些延伸探讨. 当前,数字化在给企业带来业务创新,推动企业高速发展的同时,也给企业的IT软件系 ...

最新文章

  1. 脑机互动可提高行动能力
  2. 【控制】李亚普诺夫稳定性分析
  3. 抽象工厂设计模式示例
  4. c语言无法打开源文件stdafx.h,vs2010 中无法打开 源文件 stdafx.h 未定义标识符 “xxx”...
  5. 02.C(数据类型与运算符)
  6. Sharding-Proxy读写分离_Sharding-Sphere_分库分表_读写分离_工作笔记021
  7. 51nod 2494 最长配对
  8. Debian Ubuntu/Centos7设置某些软件不自动更新
  9. 智能电网调度技术支持系统建设方案
  10. 计算机软件图标不正常,电脑桌面软件图标显示异常
  11. Acer4552G双硬盘
  12. 贾俊平统计学思维导图- 第七章参数估计
  13. pkg打包node项目文件
  14. 其实很简单 QQ被盗了可以这样找回来(转)
  15. kotlin基本语法
  16. 新版阴阳师桌面版pc端固定窗口大小多开
  17. C语言中 sinx cosx 的用法
  18. 谷歌浏览器翻译英文网页功能消失解决方案
  19. matlab算sma,[转载]通达信公式SMA函数计算方式的问题
  20. vux微信签名拿openid设计

热门文章

  1. 2020年中国新基建人工智能产业链全景图深度分析汇总(附完整企业名单)
  2. 【五社联动】 助力文明城市创建 共同缔造宜居家园
  3. 2023中职网络安全竞赛Web安全应用任务解析答案
  4. RK3328开发板固件编译记录
  5. 字段缩写ti表示什么_以下哪个字段缩写表示“摘要”?
  6. Jenkins maven自动发布配置
  7. 我用Python+PySide6做了个图形化番茄钟,这下可以提醒自己放松一下了。
  8. 4通道并行同步模拟输入,1MSps、16Bit数据采集卡
  9. iphone 4 微信版本过低
  10. 【放苹果】m个苹果放到n个盘子中