可控的异步任务-FutureTask

本文详细介绍了如何在Java中使用FutureTask进行并行任务处理,通过A、B两个耗时5秒的方法示例,展示了如何通过异步执行和get()获取结果,显著减少总耗时。

FutureTask的使用场景

针对如果有多个需要返回结果且耗时的流程的场景。
例如,A和B两个方法都耗时500ms。且都需要获取到这两个方法的返回值。如果不使用异步则需要1000ms。但是使用异步任务同时执行这两个方法,则只需要500ms


创建线程的几种方式:

  • 实现Callable接口,重写call()方法,将所要完成的任务的代码写进call()方法中,需要注意的是call()方法有返回值,并且可以抛出异常。

  • 实现Runnable接口,重写run()方法,将所要完成的任务代码写进run()方法中。

  • 继承Thread类或直接创建Thread类对象。

FutureTask的构造方法

java.util.concurrent.FutureTask.FutureTask(Callable<V> callable)

该方法需要传入一个Callable接口的实例对象。V是返回值的类型

FutureTask常用方法讲解

isDone():判断任务是否执行结束,正常执行结束,或者发生异常结束,或者被取消,都属于结束,该方法都会返回true

cancel(boolean mayInterruptIfRunning):取消子任务的执行,
如果这个子任务已经执行结束,或者已经被取消,或者不能被取消,这个方法就会执行失败并返回false;
如果子任务还没有开始执行,那么子任务会被取消,不会再被执行;
如果子任务已经开始执行了,但是还没有执行结束,根据mayInterruptIfRunning的值,
如果mayInterruptIfRunning = true,那么会中断执行任务的线程,然后返回true,
如果参数为false,会返回true,不会中断执行任务的线程

V get():获取结果,如果这个计算任务还没有执行结束,该调用线程会进入阻塞状态。
如果计算任务已经被取消,调用get()会抛出CancellationException
如果计算过程中抛出异常,该方法会抛出ExecutionException
如果当前线程在阻塞等待的时候被中断了,该方法会抛出InterruptedException

V get(long timeout, TimeUnit unit):带超时限制的get(),等待超时之后,该方法会抛出TimeoutException

FutureTask使用Demo

call_A和call_B两个方法都耗时5000ms。且都需要获取到这两个方法的返回值。将这两个耗时的操作放到FutureTask中异步执行,并使用get()获取其返回值。

package com.study.test;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 
 * @描述: Future 使用 参考 https://www.jianshu.com/p/55221d045f39
 * @版权: Copyright (c) 2020 
 * @公司: 
 * @作者: 严磊
 * @版本: 1.0 
 * @创建日期: 2020年6月28日 
 * @创建时间: 下午5:21:54
 */
public class FutureTaskDemo
{
    public static void main(String[] args) throws InterruptedException, ExecutionException
    {
        long startTime = System.currentTimeMillis();
        
        // 第一步:使用一个单独的线程执行一个耗时的操作A,并返回执行结果
        Callable<String> call_A = new Callable<String>()
        {
            @Override
            public String call() throws Exception
            {
                System.out.println("	A开始执行耗时的操作");
                Thread.sleep(5000);
                System.out.println("	A执行耗时的操作完成");
                return "耗时的操作执行结果AAAAA";
            }
            
        };
        FutureTask<String> task_A = new FutureTask<String>(call_A);
        System.out.println("启动异步任务流程A");
        new Thread(task_A).start();
        
        
        // 第二步:使用一个单独的线程执行一个耗时的操作B,并返回执行结果
        Callable<String> call_B = new Callable<String>()
        {
            @Override
            public String call() throws Exception
            {
                System.out.println("	B开始执行耗时的操作");
                Thread.sleep(5000); 
                System.out.println("	B执行耗时的操作完成");
                return "耗时的操作执行结果BBBBB";
            }
            
        };
        FutureTask<String> task_B = new FutureTask<String>(call_B);
        System.out.println("启动异步任务流程B");
        new Thread(task_B).start();
        
        // isDone() 检查A、B任务是否执行完成。任务正常终止、异常或取消,该方法都返回true
        if ( !task_A.isDone() || !task_B.isDone())
        {   
            if( !new Random().nextBoolean())
            {
            	System.out.println("取消执行耗时的操作");
            	// cancel() 尝试取消任务
            	task_A.cancel(true);
            	task_B.cancel(true);
                return;
            }
        }
        
        //第三步:获取异步执行的结果,get()方法会阻塞调用线程,直到异步任务执行完成
        String result_A = task_A.get();
        String result_B = task_B.get();
        System.out.println("A返回的结果:"+result_A);
        System.out.println("B返回的结果:"+result_B);
        
        System.out.println("总共用时" + (System.currentTimeMillis() - startTime) + "ms");
    }
}

执行结果:
可以看到这两个任务是并行执行的。只消耗了5002ms
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值