Java并发:Callable与Future

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36420790/article/details/82901528

Callable

Runnable 封装一个异步运行的任务,可以把它想象成为一个没有参数和返回值的异步方法。

Runnable runnable = new Runnable() {
    @Override
    public void run() {

    }
};

runnable.run();

Callable 和 Runnable 类似,但是有返回值,Callable 接口只有一个方法 call。

public interface Callable<V>{
    V call() throw Exception;
}
Callable<Integer> callable = new Callable<Integer>() {
    @Override
    public Integer call() throws Exception {
        
        return null;
    }
};

Integer result = callable.call();

参数类型是返回的类型,例如 Callable<Integer> 表示一个最终返回 Integer 对象的异步计算。

可以像上例一样直接执行 call() 方法,然后获取执行结果,但是,除了可以获取最终结果之外,你不能对它进行任何操作或干预。

若想监控这个计算是否执行完毕,或者试图中断它,有以下两种方案:

1.借助FutureTask包装器

将 Callable 实例作为构造参数提交给一个 FutureTask 实例,然后调用 FutureTask 实例的 run() 方法

FutureTask<Integer> task = new FutureTask<>(callable);

task.run();

在 run() 方法内部,callable 对象的 call() 方法将会被调用,计算完成后,FutureTask 会将结果保存下来,可以通过 get 方法获取计算结果

public V get()
public V get(long timeout, TimeUnit unit)

第一个 get 方法的调用被阻塞,直到计算完成。

第二个 get 方法会等待指定的时间,若时间之内计算仍然没有完成,则抛出 TimeoutException 异常。

如果计算被中断,两个 get 方法都将抛出 InterruptedException 异常。

2.将Callable提交给线程池

利用 Executors 类的工厂方法获取线程池(请参考我的另一篇文章:Executor 执行器),然后调用 submit 方法提交计算任务。

ExecutorService executor = Executors.newCachedThreadPool();

Future<Integer> future = executor.submit(callable);

submit 方法将返回一个 Future 的 实例对象,该对象包含了任务的计算结果,实际上,在上一个方案中的 FutureTask 类即是 Future 的一个实现:

FutureTask 实现了 RunnableFuture 接口

public class FutureTask<V> implements RunnableFuture<V>

 而 RunnableFuture 接口继承于 Runnable, Future 接口

public interface RunnableFuture<V> extends Runnable, Future<V> 

 

Future

Future 接口共包含五个抽象方法:

  1. cancel(boolean mayInterrupt) :可以用此方法取消计算,如果计算还没有开始,它将被取消且不再开始;若计算已经处于运行之中,且 mayInterrupt 参数为 true,则计算将被中断:这将导致对这个任务 get 方法的调用抛出 InterruptedException 异常。
  2. isCancelled() :如果该计算在完成之前被取消则返回 true。
  3. isDone() :如果任务已经完成则返回 ture (正常结束,被取消,抛出异常都视为任务完成)
  4. get() :获取计算结果,此方法阻塞调用,直到计算完成。
  5. get(long timeout, TimeUnit unit) :获取计算结果,如果计算已完成则直接返回,若没完成则等待指定的时间,时间之内计算仍没有完成,则抛出 TimeoutException 异常
public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get();
    V get(long timeout, TimeUnit unit)

 

猜你喜欢

转载自blog.csdn.net/qq_36420790/article/details/82901528