浅析Java并发编程Callable、Future、FutureTask

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

Runnable是一种有很大局限的抽象接口,虽然它的run方法能写入到日志文件或者将结果放入到共享的数据结构中,但是它不能返回一个值或抛出一个受检查的异常。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

Callable是一种更好的抽象,它的主入口call方法将返回一个值,并可能抛出一个异常。

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

Runnable和Callable描述的都是抽象的计算任务,这些任务通常是有范围的,既有一个明确的起始点,并且最终会结束。

Executor框架执行的任务有4个生命周期阶段:创建、提交、开始和完成。由于有些任务可能要执行很长的时间,因此通常希望能够取消这些任务。在Executor框架中,已提交但尚未开始执行的任务可以取消,但对于那些已经开始执行的任务,只有当它们能响应中断时,才能取消。取消一个已经完成的任务不会有任何影响。
Java的Executor框架提供了四种线程池:

  1. newCachedThreadPool将创建一个可缓存的线程池,如果线程池的当前规模超过了处理需求时,那么将回收空闲的线程,而当需求增加时,则可以添加新的线程,线程池的规模不存在任何限制。
  2. newFixedThreadPool将创建一个固定 长度的线程池,每当提交一个任务时就 创建一个线程,直到达到线程池的最大数量,这时线程池的规模将不再变化,超出的 线程将在队列中等待。
  3. newSingleThreadExecutor是一个单线程Executor,它创建单个工作者线程来执行任务,如果这个线程异常结束,会创建另一个线程来替代;newSingleThreadExecutor能确保依照任务在队列中的顺序来串行执行(如:FIFO,LIFO、优先级)
  4. newScheduledThreadPool创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务。

Future表示一个任务的生命周期,并提供了相应的方法来判断是否已经完成或取消,以及获取任务的结果和取消任务等。

Future是一个接口,位于java.util.concurrent包下:

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

Future接口一共声明了5个方法,下面解释每一个方法的作用:

  1. cancel方法用来取消任务,如果取消任务 成功则返回ture,否则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行,但是没有结束的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
  2. isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
  3. isDone方法表示任务是否已经完成,若任务完成,则返回true;
  4. get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
  5. get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。
    因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。

FutureTask实现了Future语义,表示一种抽象的可生成结果的计算;它表示的计算是通过Callable来实现的,相当于一种可生成结果的Runnable,并且可以处于以下三种状态:等待运行、正在运行和运行完毕。

我们先看一下FutureTask的实现:

public class FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

我们可以看到FutureTask接口实现了RunnableFuture接口,而Runnable接口又继承了Runnable和Future接口,所以它既可以作为一个线程的任务来执行,又可以作为Future通过Callable得到返回值。

事实上FutureTask是Future接口的唯一实现类。

猜你喜欢

转载自blog.csdn.net/yaomingyang/article/details/88774514