Callable, Runnable, Future, FutureTask

Java并发编程之Callable, Runnable, Future, FutureTask

  Java中存在Callable, Runnable, Future, FutureTask这几个与线程相关的类或接口, 下面来了解一下它们的作用和区别.

一.Callable和Runnable

  Callable和Runnable类似, 实现Callable和Runnable接口的类都是可以被其他线程运行的任务, Callable和Runnable主要有以下几点区别:

(1). Callable中声明的方法是call(), Runnable中声明的方法是run().

(2). Callable任务执行后可返回值, Runnable任务执行后没有返回值.

(3). call()方法可以抛出异常, run()方法不能抛出异常.

(4). 运行Callable任务可以拿到一个Future对象.

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

 public interface Runnable {
     /**
      * When an object implementing interface <code>Runnable</code> is used
      * to create a thread, starting the thread causes the object's
      * <code>run</code> method to be called in that separately executing
      * thread.
      * <p>
      * The general contract of the method <code>run</code> is that it may
      * take any action whatsoever.
      *
      * @see     java.lang.Thread#run()
      */
     public abstract void run();
 }

二. Future对象

  Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。可以通过get()方法获取执行结果, get()方法会阻塞,直到任务返回结果

public interface Future<V> {

    /**
     * Attempts to cancel execution of this task.  This attempt will
     * fail if the task has already completed, has already been cancelled,
     * or could not be cancelled for some other reason. If successful,
     * and this task has not started when <tt>cancel</tt> is called,
     * this task should never run.  If the task has already started,
     * then the <tt>mayInterruptIfRunning</tt> parameter determines
     * whether the thread executing this task should be interrupted in
     * an attempt to stop the task.
     *
     * <p>After this method returns, subsequent calls to {@link #isDone} will
     * always return <tt>true</tt>.  Subsequent calls to {@link #isCancelled}
     * will always return <tt>true</tt> if this method returned <tt>true</tt>.
     *
     * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
     * task should be interrupted; otherwise, in-progress tasks are allowed
     * to complete
     * @return <tt>false</tt> if the task could not be cancelled,
     * typically because it has already completed normally;
     * <tt>true</tt> otherwise
     */
    boolean cancel(boolean mayInterruptIfRunning);

    /**
     * Returns <tt>true</tt> if this task was cancelled before it completed
     * normally.
     */
    boolean isCancelled();

    /**
     * Returns <tt>true</tt> if this task completed.
     * Completion may be due to normal termination, an exception, or
     * cancellation -- in all of these cases, this method will return
     * <tt>true</tt>.
     */
    boolean isDone();

    /**
     * Waits if necessary for the computation to complete, and then
     * retrieves its result.
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * Waits if necessary for at most the given time for the computation
     * to complete, and then retrieves its result, if available.
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

下面依次解释每个方法的作用:

  • cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数 mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如 果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返 回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若 mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论 mayInterruptIfRunning为true还是false,肯定返回true。
  • isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
  • isDone方法表示任务是否已经完成,若任务完成,则返回true;
  • get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
  • get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。

  也就是说Future提供了三种功能:

  1)判断任务是否完成;

  2)能够中断任务;

  3)能够获取任务执行结果。

  因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。

三. FutureTask

  我们先来看一下FutureTask的实现:

public class FutureTask<V> implements RunnableFuture<V> {

}

  FutureTask类实现了RunnableFuture接口,我们看一下RunnableFuture接口的实现:

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

  可以看出RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

  FutureTask提供了2个构造器:

public FutureTask(Callable<V> callable) {
    }

public FutureTask(Runnable runnable, V result) {
    }

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

简单示例:

import java.util.concurrent.*;

/**
 * Created by xinfengyao on 16-2-17.
 */
public class RunnableFutureTest {
    static ExecutorService executorService = Executors.newCachedThreadPool();

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        runnableDemo();
        futureDemo();
    }

    /**
     * Runnable无返回值
     */
    static void runnableDemo() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("runnable demo: " + fibc(20));
            }
        }).start();
    }

    /**
     * 其中Runnable实现的是void run()方法,无返回值;Callable实现的是 V
     * call()方法,并且可以返回执行结果。其中Runnable可以提交给Thread来包装下
     * ,直接启动一个线程来执行,而Callable则一般都是提交给ExecuteService来执行。
     */
    static void futureDemo() throws ExecutionException, InterruptedException {
        /**
         * 提交runnable则没有返回值, future没有数据
         */
        Future<?> result = executorService.submit(new Runnable() {
            @Override
            public void run() {
                fibc(20);
            }
        });
        System.out.println("future result from runnable: " + result.get());

        /**
         * 提交Callable, 有返回值, future中能够获取返回值
         */
        Future<Integer> result2 = executorService.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return fibc(20);
            }
        });
        System.out.println("future result from callable: " + result2.get());

        /**
         * FutureTask则是一个RunnableFuture<V>,既实现了Runnable又实现了Future<V>这两个接口,
         * 另外它还可以包装Runnable(实际上会转换为Callable)和Callable
         * <V>,所以一般来讲是一个复合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行
         * ,并且还可以通过v get()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。
         */
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return fibc(20);
            }
        });
        // 提交futureTask
        executorService.submit(futureTask);
        System.out.println("future result from futureTask: " + futureTask.get());
    }

    static int fibc(int n) {
        if (n==0 || n==1) {
            return n;
        }
        return fibc(n-1) + fibc(n-2);
    }

}

运行结果:

runnable demo: 6765
future result from runnable: null
future result from callable: 6765
future result from futureTask: 6765
上一篇:java中有关线程的题目


下一篇:SQLite 命令