【Future】Future和Callable的运用

Runnable接口没有返回值,并且不能抛出已检查异常,只能捕获。

为什么Runnable设计成不能抛出异常?
如果run方法抛出异常,Thread类来接收(run()的执行者是Thread类)。Thread类包括线程池以及能够执行run方法的类,大部分情况下不是我们编写。所以就算是在run方法上抛出异常,处理也不是我们编写。能处理异常的地方就是run方法中。

@FunctionalInterface
public interface Callable<V> {
    
    
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

使用Future获取Callable任务结果

Future可以视作一个存储器,存储call()这个任务的结果。future.get获取Callable接口返回的结果。如果call()未执行完毕,调用get()的线程会阻塞,直到call任务结束。

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

核心方法get(),主要存在三种情况:

  1. 任务正常完成,返回结果
  2. 任务执行过程中,get方法阻塞直到完成
  3. 抛出异常(执行、中断、任务取消、超时四种)
    异常抛出的时机:调用future的get方法。

cancel()方法

  • 任务未执行,则任务会被取消,返回true。
  • 任务已完成,或者已取消,返回false。
  • 任务在执行中,根据参数判断。参数true,发送一个中断信号;false不发送。

cancel方法传入false,对于执行中的任务没有意义,用于避免启动还未启动的线程。

public class FutureDemo {
    
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    
        ExecutorService pool = Executors.newFixedThreadPool(10);
        Callable<Integer> callable = () -> {
    
    
            TimeUnit.SECONDS.sleep(3);
            return (int) (Math.random() * 10);
        };
        Future<Integer> future = pool.submit(callable);
        System.out.println(future.get());
    }
}

使用FutureTask创建Future

FutureTask对Callable任务进行封装,作为任务使用,
在这里插入图片描述

public class FutureTaskDemo {
    
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    
        ExecutorService pool = Executors.newFixedThreadPool(10);
        Callable<Integer> callable = () -> {
    
    
            TimeUnit.SECONDS.sleep(3);
            return (int) (Math.random() * 10);
        };
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        pool.submit(futureTask);
        System.out.println(futureTask.get());
    }
}

Future使用的注意点

Future使用的注意点:

  1. 生命周期不能回退,一旦结束不能从头再来。
  2. 使用循环批量获取future时,如果有一部分线程较慢,会阻塞其他线程。可以采用get的timeout限制。
List<Future> futures = new ArrayList<>();
for (int i = 0; i < 20; i++) {
    
    
	Future<Integer> future = service.submit(new CallableTask());
	futures.add(future);
}

猜你喜欢

转载自blog.csdn.net/LIZHONGPING00/article/details/114622392