并发编程(十四)-Future使用

本文详细介绍了Java中的Future接口及其典型实现FutureTask的使用方法。Future表示异步计算的结果,提供了检查计算状态、获取结果和取消任务的功能。FutureTask结合线程池可以高效执行异步任务,通过get()方法获取结果或使用isDone()进行轮询检查。文章还展示了FutureTask在实际代码中的应用示例,突出了其在多线程环境中的优势和潜在问题,如阻塞和资源消耗。
摘要由CSDN通过智能技术生成

二、Future

1. 描述

  • Future 表示异步计算的结果。
  • 提供了检查计算是否完成、等待其完成以及检索计算结果的方法。
  • 结果只能在计算完成后使用方法 get 检索,必要时阻塞,直到它准备好。
  • 取消是通过取消方法执行的。提供了额外的方法来确定任务是正常完成还是被取消。一旦计算完成,就不能取消计算。
  • 如果想使用 Future 来取消可取消性但不提供可用的结果,您可以声明 Future<?> 形式的类型并返回 null 作为底层任务的结果。

Future源码:

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;
}

2. 使用

  • 如果主线程需要执行一个很耗时的任务,可以通过Future把这个任务放到异步线程中执行
  • 主线程继续处理其他任务或者先行结束,可以通过get获取计算结果
  • 一句话总结:Future接口可以为主线程开一个异步线程,专门为主线程执行耗时任务

Future接口的实现类需要满足3个特点:多线程、有返回值、执行异步任务
FutureTask实现类可以满足以上3个特点
在这里插入图片描述

  • FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况。
public static void main(String[] args) throws ExecutionException, InterruptedException {

       // 创建任务对象
       FutureTask<Integer> futureTask = new FutureTask(() -> {
           log.debug("callable执行任务");
           Thread.sleep(1000);
           return 100;
       });

       // 参数1 是任务对象; 参数2 是线程名
       Thread t1 = new Thread(futureTask, "t1");
       t1.start();

       // 主线程阻塞,同步等待 futureTask 执行完毕的结果
       Integer result = futureTask.get();
       // 1秒后获取到结果
       log.debug("获取FutureTask结果:{}", result);
   }
22:36:52.884 c.FutureTaskThread [t1] - callable执行任务
22:36:53.899 c.FutureTaskThread [main] - 获取FutureTask结果:100

Process finished with exit code 0

Callable源码

// Callable是函数式接口,有返回结果,能抛出异常
@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

FutureTask源码

// 1.FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况,get方法可以获取返回结果
// 2.FutureTask类是 Runnable接口 的扩展,FutureTask 既有Runnable中的run方法,又有Future中的get方法
public class FutureTask<V> implements RunnableFuture<V> {
  public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
}

// 接口可以多继承
public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}
  • 优点:FutureTask配合线程池执行异步任务,可以提升执行效率
@Slf4j(topic = "c.TestFutureTask")
public class TestFutureTask {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(3);

        long start = System.currentTimeMillis();

        FutureTask<Integer> task1 = new FutureTask<>(() -> {
            Thread.sleep(1000);
            return 1;
        });
        pool.submit(task1);

        FutureTask<Integer> task2 = new FutureTask<>(() -> {
            Thread.sleep(2000);
            return 2;
        });
        pool.submit(task2);

        FutureTask<Integer> task3 = new FutureTask<>(() -> {
            Thread.sleep(3000);
            return 3;
        });
        pool.submit(task3);
        log.debug("{}", task1.get());
        log.debug("{}", task2.get());
        log.debug("{}", task3.get());

        long end = System.currentTimeMillis();
        log.debug("总耗时:{}毫秒", end - start);
        pool.shutdown();
    }
}
16:08:38.938 c.TestFutureTask [main] - 1
16:08:39.931 c.TestFutureTask [main] - 2
16:08:40.934 c.TestFutureTask [main] - 3
16:08:40.934 c.TestFutureTask [main] - 总耗时:3065毫秒
  • isDone()轮询获取异步任务结果
@Slf4j(topic = "c.TestFutureTask")
public class TestFutureTask {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(1);

        long start = System.currentTimeMillis();

        FutureTask<Integer> task1 = new FutureTask<>(() -> {
            Thread.sleep(3000);
            return 1;
        });
        pool.submit(task1);

        while (true) {
            if (task1.isDone()) {
                log.debug("{}", task1.get());
                break;
            } else {
                Thread.sleep(500);
                log.debug("正在处理中,请等到。。。。");
            }
        }

        long end = System.currentTimeMillis();
        log.debug("总耗时:{}毫秒", end - start);
        pool.shutdown();
    }
}
16:24:00.121 c.TestFutureTask [main] - 正在处理中,请等到。。。。
16:24:00.632 c.TestFutureTask [main] - 正在处理中,请等到。。。。
16:24:01.139 c.TestFutureTask [main] - 正在处理中,请等到。。。。
16:24:01.644 c.TestFutureTask [main] - 正在处理中,请等到。。。。
16:24:02.150 c.TestFutureTask [main] - 正在处理中,请等到。。。。
16:24:02.666 c.TestFutureTask [main] - 正在处理中,请等到。。。。
16:24:02.666 c.TestFutureTask [main] - 1
16:24:02.667 c.TestFutureTask [main] - 总耗时:3101毫秒

FutureTask缺点:

  • get()阻塞,调用get方法计算结果,如果计算没有完成容易导致程序阻塞
  • isDone()轮询会耗费无畏的CPU资源,并且也不能及时得到计算结果
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值