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知识库 -> Java中Future和FutureTask详解及使用 -> 正文阅读

[Java知识库]Java中Future和FutureTask详解及使用

一、Future 接口

当 call()方法完成时,结果必须存储在主线程已知的对象中,以便主线程可以知道该线程返回的结果。为此,可以使用 Future 对象。
将 Future 视为保存结果的对象–它可能暂时不保存结果,但将来会保存(一旦Callable 返回)。Future 基本上是主线程可以跟踪进度以及其他线程的结果的一种方式。要实现此接口,必须重写 5 种方法,这里列出了重要的方法,如下:

public boolean isDone()

在这里插入图片描述

public boolean cancel(boolean mayInterruptIfRunning)

用于停止任务。如果尚未启动,它将停止任务。如果已启动,则仅在 mayInterrupt 为 true时才会中断任务。

在这里插入图片描述

boolean isCancelled()

如果任务在正常结束之前被取消返回true

public V get() throws InterruptedException, ExecutionException

用于获取任务的结果。如果任务完成,它将立即返回结果,否则将等待任务完成,然后返回结果。

public V get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException

如果任务完成,则返回 true,否则返回 false。

Callable 与 Runnable 类似,因为它封装了要在另一个线程上运行的任务,而 Future 用于存储从另一个线程获得的结果

实际上,Future 也可以与 Runnable 一起使用。要创建线程,需要 Runnable。为了获得结果,需要 future。

二、FutureTask

介绍:当一个线程需要等待另一个线程把某个任务执行完后它才能继续执行,此时可以使用FutureTask。假设有多个线程执行若干任务,每个任务最多只能被执行一次。当多个线程试图同时执行同一个任务时,只允许一个线程执行任务,其他线程需要等待这个任务执行完后才能继续执行。

Java 库具有具体的 FutureTask 类型,该类型实现 Runnable 和 Future,并方便地将两种功能组合在一起。 可以通过为其构造函数提供 Callable 来创建FutureTask。然后,将 FutureTask 对象提供给 Thread 的构造函数以创建Thread 对象因此,间接地使用 Callable 创建线程

FutureTask状态转换

FutureTask有以下7种状态:

FutureTask任务的运行状态,最初为NEW。运行状态仅在set、setException和cancel方法中转换为终端状态。在完成过程中,状态可能呈现出瞬时值INTERRUPTING(仅在中断运行程序以满足**cancel(true)**的情况下)或者COMPLETING(在设置结果时)状态时。从这些中间状态到最终状态的转换使用成本更低的有序/延迟写,因为值是统一的,需要进一步修改。

state:表示当前任务的运行状态,FutureTask的所有方法都是围绕state开展的,state声明为volatile,保证了state的可见性,当对state进行修改时所有的线程都会看到

NEW:表示一个新的任务,初始状态
COMPLETING:当任务被设置结果时,处于COMPLETING状态,这是一个中间状态。
NORMAL:表示任务正常结束。
EXCEPTIONAL:表示任务因异常而结束
CANCELLED:任务还未执行之前就调用了cancel(true)方法,任务处于CANCELLED
INTERRUPTING:当任务调用cancel(true)中断程序时,任务处于INTERRUPTING状态,这是一个中间状态。
INTERRUPTED:任务调用cancel(true)中断程序时会调用interrupt()方法中断线程运行,任务状态由INTERRUPTING转变为INTERRUPTED

可能的状态过渡:
1、NEW -> COMPLETING -> NORMAL:正常结束
2、NEW -> COMPLETING -> EXCEPTIONAL:异常结束
3、NEW -> CANCELLED:任务被取消
4、NEW -> INTERRUPTING -> INTERRUPTED:任务出现中断

三、使用 Callable 和 Future

Runnable缺少的一项功能是,当线程终止时(即 run()完成时),我们无法使线程返回结果。

为了支持此功能,Java 中提供了 Callable 接口。不能直接替换 runnable,因为 Thread 类的构造方法根本没有 Callable。

所以我们可以找一个中间人,也就是FutureTask。

在这里插入图片描述

在这里插入图片描述

案例

class MyThreadA implements Callable {
    @Override
    public Object call() throws Exception {
        System.out.println(Thread.currentThread().getName() + "在call方法里");
        System.out.println(Thread.currentThread().getName() + "线程进入了 call方法,开始睡觉(进行了一些计算)");
        Thread.sleep(10000);
        System.out.println(Thread.currentThread().getName() + "睡醒了");
        return Thread.currentThread().getName() + "返回的:" + System.currentTimeMillis();
    }
}


public class demo1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTaskA = new FutureTask<>(new MyThreadA());

        FutureTask<String> futureTaskB = new FutureTask<>(()->{
            System.out.println(Thread.currentThread().getName() + "在call方法里");
            return Thread.currentThread().getName() + "返回的:" + System.currentTimeMillis();
        });

        new Thread(futureTaskA,"线程A").start();
        new Thread(futureTaskB,"线程B").start();

        while (!futureTaskB.isDone()){  //isDone表示FutureTask的计算是否完成
            System.out.println("wait.......");
        }
        System.out.println(futureTaskA.get());
        System.out.println(futureTaskB.get());

        System.out.println(Thread.currentThread().getName() + "结束了");
    }
}

输出结果:

在这里插入图片描述

由上图两个线程返回的时间差约等于10秒可以看出,当一个线程(线程B)需要等待(一直wait…)另一个线程(线程A)把某个任务(进行了一些计算)执行完后它才能继续执行,此时可以使用FutureTask。不管futureTaskA.get()和futureTaskB.get()谁在前面,输出结果一定是“线程B返回的:xxx”在“wait…”的后面。假设有多个线程执行若干任务,每个任务最多只能被执行一次。当多个线程试图同时执行同一个任务时,只允许一个线程执行任务,其他线程需要等待这个任务执行完后才能继续执行。

四、小结(FutureTask核心原理)

FutureTask核心原理

在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些作业交给 Future 对象在后台完成,当主线程将来需要时,就可以通过 Future对象获得后台作业的计算结果或者执行状态。
? 一般 FutureTask 多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果
? 仅在计算完成时才能检索结果;如果计算尚未完成,则阻塞 get 方法。一旦计算完成,就不能再重新开始或取消计算。get 方法而获取结果只有在计算完成时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常。
? get只计算一次,因此 get 方法放到最后

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-30 15:28:34  更:2021-11-30 15:29:53 
 
开发: 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 4:16:56-

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