多线程之 Callable Future FutureTask

JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程

一、Callable
Runnable和Callable的区别是:
(1)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
(2)call方法可以抛出异常,run方法不可以
源码如下:

/**
 * <p>The {@code Callable} interface is similar to {@link
 * java.lang.Runnable}, in that both are designed for classes whose
 * instances are potentially executed by another thread.  A
 * {@code Runnable}, however, does not return a result and cannot
 * throw a checked exception.
 */
@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
Future就是对于具体的Runnable或者Callable任务的操作,可以取消、查询是否取消、是否完成、获取结果。
源码:

public interface Future<V> {
    /**
     * @param mayInterruptIfRunning 任务执行期间是否可以取消,true可以,false不可以
     * @return  无论mayInterruptIfRunning true或false,只要任务已经执行完成则返回false,否则true
     */
    boolean cancel(boolean mayInterruptIfRunning);

    /**
     * 任务执行之前或者正常完成之前被取消返回true
     */
    boolean isCancelled();

    /**
     * 任务完成,返回true,被取消除外
     */
    boolean isDone();

    /**
     * 获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * 用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

三、FutureTask
由上可知,Future是一个接口,没有具体的实现可以使用,FutureTask就是Future的实现:
RunnableFuture继承Runnable 、Future:

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}
FutureTask类实现了RunnableFuture接口:
public class FutureTask<V> implements RunnableFuture<V> {
}
FutureTask的构造函数:
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

FutureTask的run方法


public void run() {

      if (state != NEW ||
          !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                       null, Thread.currentThread()))
          return;
      try {
          Callable<V> c = callable;
          if (c != null && state == NEW) {
              V result;
              boolean ran;
              try {
                  result = c.call();
                  ran = true;
              } catch (Throwable ex) {
                  result = null;
                  ran = false;
                  setException(ex);
              }
              if (ran)
                  set(result);
          }
      } finally {
          // runner must be non-null until state is settled to
          // prevent concurrent calls to run()
          runner = null;
          // state must be re-read after nulling runner to prevent
          // leaked interrupts
          int s = state;
          if (s >= INTERRUPTING)
              handlePossibleCancellationInterrupt(s);
      }
  }

如果任务执行成功,则把返回结果set(V v)方法存储,方法如下:

protected void set(V v) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = v;
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        finishCompletion();
    }
}

若执行发生异常,则调用setException()方法保存异常信息,方法如下:

 protected void setException(Throwable t) {
     if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
         outcome = t;
         UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
         finishCompletion();
     }
 }

获取结果则是get()方法,如下:


public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
        s = awaitDone(false, 0L);
    return report(s);
}

具体结果返回是通过report()方法操作:

private V report(int s) throws ExecutionException {
     Object x = outcome;
     if (s == NORMAL)
         return (V)x;
     if (s >= CANCELLED)
         throw new CancellationException();
     throw new ExecutionException((Throwable)x);
 }

如果state的状态为NORMAL,返回计算后的值;如果state的状态大于等于CANCELLED,说明任务被成功取消执行、或响应中断,则返回CancellationException异常,否则返回ExecutionException异常。

四、使用
Future、FutureTask的使用要配合Excutor的使用,ExecutorService中的submit方法接受一个Runnable或者Callable,然后返回一个Future来获得任务的执行结果或者取消任务。

public interface ExecutorService extends Executor {
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
}

例子:

public static void main(String[] arg){
    ExecutorService executor = Executors. newCachedThreadPool();
    FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            return 1;
        }
    });
    Future f =executor.submit(futureTask);
    Future f1 =executor.submit(new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            return 2;
        }
    });
    executor.shutdown();
    try {
        Thread. sleep(1000);
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    }
    System. out.println("主线程在执行任务" );
    try {
        System. out.println("task运行结果" + futureTask.get());
        System. out.println("task运行结果" + f.get());
        System. out.println("task运行结果" + f1.get());
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    System. out.println("所有任务执行完毕" );
}

注:FutureTask 在submit的时候不需要返回future对象,自己就可以get到结果,Callable Runnable需要返回Future才能获取结果;

这段代码中返回的Future是新建的对象,FutureTask为什么结果值不是在返回的对象之中呢?

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
   return new FutureTask<T>(runnable, value);
}

通过这段代码我们可以知道,直接传入FutureTask会被当做Runnable对象进行处理,继续深入就会发现FutureTask会被RunnableAdapter进行适配,我们在外层的Future是无法获取返回结果的,但是其内部的FutureTask是有返回值的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值