我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java中Future和FutureTask的示例详解及使用

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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 方法放到最后

附:FutureTask在高并发环境下确保任务只执行一次

网上有篇例子,但是中间讲的不是很清楚。我重新梳理了一下。

在很多高并发的环境下,往往我们只需要某些任务只执行一次。这种使用情景FutureTask的特性恰能胜任。举一个例子,假设有一个带key的连接池,当key存在时,即直接返回key对应的对象;当key不存在时,则创建连接。对于这样的应用场景,通常采用的方法为使用一个Map对象来存储key和连接池对应的对应关系,典型的代码如下面所示:


package com.concurrency.chapter15;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;


public class FutureTaskConnection1 {

    private static Map<String, Connection> connectionPool = new HashMap<>();
    private static ReentrantLock lock = new ReentrantLock();

    public static Connection getConnection(String key) {
        try {
            lock.lock();
            Connection connection = connectionPool.get(key);
            if (connection == null) {
                Connection newConnection = createConnection();
                connectionPool.put(key, newConnection);
                return newConnection;
            }
            return connection;
        } finally {
            lock.unlock();
        }
    }

    private static Connection createConnection() {
        try {
            return DriverManager.getConnection("");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}

总结

到此这篇关于Java中Future和FutureTask的文章就介绍到这了,更多相关Java Future和FutureTask使用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java中Future和FutureTask的示例详解及使用

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

java多线程编程同步器Future和FutureTask解析及代码示例

publicinterfaceFutureFuture表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用get方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由canc
2023-05-30

Java实现FutureTask的示例详解

在并发编程当中我们最常见的需求就是启动一个线程执行一个函数去完成我们的需求,而在这种需求当中,我们需要函数有返回值。Java给我们提供了这种机制,去实现这一个效果:FutureTask。本文为大家准备了Java实现FutureTask的示例代码,需要的可以参考一下
2022-11-13

Java中如何使用Callable和Future接口详解

本篇文章给大家分享的是有关Java中如何使用Callable和Future接口详解,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Runnable是一个接口,而Thread是Ru
2023-06-20

react中使用antd及immutable示例详解

这篇文章主要为大家介绍了react中使用antd及immutable示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

python Fabric使用详解及示例

abric是基于Python实现的SSH命令行工具,简化了SSH的应用程序部署及系统管理任务,它提供了系统基础的操作组件,可以实现本地或远程shell命令,包括:命令执行、文件上传、下载及完整执行日志输出等功能。Fabric在Paramik
2023-01-31

TreeSet详解和使用示例

TreeSet是Java集合框架中的一个类,它实现了SortedSet接口,底层使用红黑树实现,可以实现有序的插入和遍历。TreeSet的特点:1. TreeSet中的元素是有序的,默认按照升序排序,也可以通过Comparator自定义排序
2023-08-08

Java中的vector类使用方法示例详解

基本操作示例VectorApp.javaimport java.util.Vector; import java.lang.*; import java.util.Enumeration; public class VectorApp {
2023-05-31

ESLint和Jest中使用esm示例详解

这篇文章主要为大家介绍了ESLint和Jest中使用esm示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-03-03

Zookeeper原理及在Dubbo中的使用示例详解

这篇文章主要为大家介绍了Zookeeper原理及在Dubbo中的使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-03-19

Java中使用同步回调和异步回调的示例详解

这篇文章主要介绍了Java中使用同步回调和异步回调的相关资料,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-05-16

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录