首页 > 编程语言 >Java多线程:Future和FutureTask

Java多线程:Future和FutureTask

时间:2023-02-01 15:34:51浏览次数:63  
标签:task Java ftask Future static FutureTask 多线程 public

一、Future

Future是一个接口,所有方法如下:

image.png

上源码:

package java.util.concurrent;
public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();
    
    V get() throws InterruptedException, ExecutionException;
   
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}
  • cancel:取消任务(mayInterruptIfRunning是否中断正在执行的任务)。
  • isCancelled:任务是否取消
  • isDone:任务是否执行完成。
  • get:获取任务结果
  • get(long timeout, TimeUnit unit):有等待时间的获取任务结果。

二、FutureTask

FutureTask是一个类,实现了RunnableFuture接口,RunnableFuture接口继承了RunnableFuture,关系图如下:

image.png

FutureTask有两个构造函数:

public FutureTask(Callable<V> 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
}

第一个构造函数传入一个Callable对象,第二个构造函数传入Runnable对象和一个V类型的对象,然后在函数中将这两个参数构造成一个Callable对象。可见FutureTaskFuture的核心就是要执行Callable并获取返回结果。

FutureTask中的几种状态:

/**
 *
 * 可能的状态转换:
 * NEW -> COMPLETING -> NORMAL
 * NEW -> COMPLETING -> EXCEPTIONAL
 * NEW -> CANCELLED
 * NEW -> INTERRUPTING -> INTERRUPTED
 */
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;

查看源码,发现状态共有七种,初始化为NEW,运行时仅在set、setException和cancel方法中会转换为终端状态。终端状态共四种:NORMAL结果正常、EXCEPTIONAL结果异常、CANCELLED任务取消、INTERRUPTED任务中断,可能的状态转换源码中注释已写清楚。

三、示例

Future在线程池中主要做为一个返回(submit方法),用于接收执行完成的结果,FutureTask则是具体实现。
测试代码:

public class ExecutorTest1 {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        ExecutorTest1 test1 = new ExecutorTest1();
        Future<String> futureTest = executorService.submit(() -> test1.say("测试返回值"));
        executorService.shutdown();
    }

    public String say(String a){
        System.out.println("执行了say方法");
        return "test"+a;
    }

}

以上代码,执行了say方法,获取到了futureTest对象,但是futureTest对象不能直接使用,需要调用get方法获取结果,以上代码执行结果:

image.png

获取Future对象结果代码示例:

public class ExecutorTest1 {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        ExecutorTest1 test1 = new ExecutorTest1();
        Future<String> futureTest = executorService.submit(() -> test1.say("测试返回值"));
        try {
            String s = futureTest.get();
            System.out.println(s);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
    }

    public String say(String a){
        System.out.println("执行了say方法");
        return "test"+a;
    }

}

可见要执行有返回值的线程,需要用Future来接收。那么FutureTask在哪里使用了呢,在执行方法的时候将传入的Callable对象或者Runnable对象封装成FutureTask对象,源码如下:

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}

public <T> Future<T> submit(Runnable task, T result) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task, result);
    execute(ftask);
    return ftask;
}

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}

newTaskFor方法如下:

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

四、结果

Future和FutureTask的核心作用是获取有返回值的线程结果。

Java多线程:Future和FutureTask

Java线程池详解

标签:task,Java,ftask,Future,static,FutureTask,多线程,public
From: https://www.cnblogs.com/weiqihome/p/17082951.html

相关文章

  • 使用java python 实现 QI-页面排序-骑马钉
    链接:http://www.cnprint.org/bbs/thread/77/339531/......
  • Spring开启@Async异步方法(javaconfig配置)
    在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。应用场景:某些耗时较长的......
  • JavaScript闭包的概念
    什么是闭包?闭包有什么作用,缺点是什么?闭包的概念:JavaScript中函数会产生闭包(closure)。闭包是函数本身和该函数声明时所处的环境状态的组合;函数能够“记忆住”其定义......
  • Java 多态
    多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编译时并不确定,而是在程序运行期间才确定。即一个引用变量倒底会指向哪个类的实例对象......
  • 多线程知识点
    1.理论产生死锁的四个条件互斥条件:一个资源同时只能被一个线程占用请求与保持条件:一个进程因请求资源而阻塞时,对已获得资源不释放不剥夺条件:一个进程已获得的资源,在不......
  • 使用Disruptor完成多线程下并发、等待、先后等操作
    Java完成多线程间的等待功能:场景1:一个线程等待其他多个线程都完成后,再进行下一步操作(如裁判员计分功能,需要等待所有运动员都跑完后,才去统计分数。裁判员和每个运动员都是一......
  • 部署在docker里的java程序获取真实的用户ip地址
    目前我们的服务都是全部docker化,网关zuul和各微服务都部署在docker里,构成了集群。用户请求全部到HaProxy,由HaProxy转发到zuul,再由zuul分发给各微服务。那么我们在做黑名单,或......
  • Java基础系列二、代码结构+函数
    代码结构顺序结构判断结构选择结构循环结构if语句的三种格式第一种if(条件表达式){...;}...;第二种if(条件表达式){...;}else{...;}......
  • Java基础系列五、类+包
    抽象类(abstract)(1)只抽取了很多类的方法的声明,为了保证不出问题,方法声明用abstract修饰(2)抽象类的特点A:一个类如果有了抽象方法,那么这个类必须是抽象类。抽象类里边......
  • java正则表达式不包含特殊字符验证
    原文链接:https://blog.csdn.net/weixin_39625782/article/details/114674258packagecom.sodii.regex.demo;importjava.util.regex.Matcher;importjava.util.regex.Pa......