首頁  >  文章  >  Java  >  Java concurrency執行緒池之關於Callable和Future的程式碼詳解

Java concurrency執行緒池之關於Callable和Future的程式碼詳解

黄舟
黄舟原創
2017-06-18 10:11:141497瀏覽

這篇文章主要為大家詳細介紹了Java concurrency線程池之Callable和Future,具有一定的參考價值,有興趣的小伙伴們可以參考一下

Callable 和Future 簡介

  Callable 和Future 是比較有趣的一對組合。當我們需要取得執行緒的執行結果時,就需要用到它們。 Callable用於產生結果,Future用於取得結果。

1. Callable

Callable 是一個接口,它只包含一個call()方法。 Callable是一個傳回結果並且可能拋出異常的任務。
為了方便理解,我們可以將Callable比喻為一個Runnable接口,而Callable的call()方法則類似Runnable的run()方法。
Callable的原始碼如下:


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

說明:從中我們可以看出Callable支援泛型。 

2. Future

Future 是一個介面。它用於表示非同步計算的結果。提供了檢查計算是否完成的方法,以等待計算的完成,並獲得計算的結果。
Future的原始碼如下:


public interface Future<V> {
 // 试图取消对此任务的执行。
 boolean cancel(boolean mayInterruptIfRunning)

 // 如果在任务正常完成前将其取消,则返回 true。
 boolean isCancelled()

 // 如果任务已完成,则返回 true。
 boolean isDone()

 // 如有必要,等待计算完成,然后获取其结果。
 V  get() throws InterruptedException, ExecutionException;

 // 如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。
 V  get(long timeout, TimeUnit unit)
  throws InterruptedException, ExecutionException, TimeoutException;
}

#說明:# Future用來表示非同步計算的結果。它的實作類別是FutureTask,在講解FutureTask之前,我們先來看看Callable, Future, FutureTask它們之間的關係圖,如下:

說明:

(01) RunnableFuture是一個接口,它繼承了Runnable和Future這兩個介面。 RunnableFuture的原始碼如下:


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

(02) FutureTask實作了RunnableFuture介面。所以,我們也說它實作了Future介面。

範例與原始碼分析(基於JDK1.7.0_40)

我們先透過一個範例看看Callable和Future的基本用法,然後再分析範例的實現原理。


import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ExecutionException;

class MyCallable implements Callable {

 @Override 
 public Integer call() throws Exception {
 int sum = 0;
 // 执行任务
 for (int i=0; i<100; i++)
  sum += i;
 //return sum; 
 return Integer.valueOf(sum);
 } 
}

public class CallableTest1 {

 public static void main(String[] args) 
 throws ExecutionException, InterruptedException{
 //创建一个线程池
 ExecutorService pool = Executors.newSingleThreadExecutor();
 //创建有返回值的任务
 Callable c1 = new MyCallable();
 //执行任务并获取Future对象 
 Future f1 = pool.submit(c1);
 // 输出结果
 System.out.println(f1.get()); 
 //关闭线程池 
 pool.shutdown(); 
 }
}

執行結果:

4950

結果說明:

  在主執行緒main中,透過newSingleThreadExecutor()新建一個執行緒池。接著建立Callable物件c1,然後再透過pool.submit(c1)將c1提交到執行緒池中進行處理,並且將傳回的結果儲存到Future物件f1中。然後,我們透過f1.get()取得Callable中儲存的結果;最後透過pool.shutdown()關閉執行緒池。

1. submit()

#submit()在java/util/concurrent/AbstractExecutorService.java中實現,它的原始碼如下:


public <T> Future<T> submit(Callable<T> task) {
 if (task == null) throw new NullPointerException();
 // 创建一个RunnableFuture对象
 RunnableFuture<T> ftask = newTaskFor(task);
 // 执行“任务ftask”
 execute(ftask);
 // 返回“ftask”
 return ftask;
}

說明:submit()透過newTaskFor(task)建立了RunnableFuture物件ftask。它的原始碼如下:


protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
 return new FutureTask<T>(callable);
}

2. FutureTask的建構子

FutureTask的建構子如下:


public FutureTask(Callable<V> callable) {
 if (callable == null)
 throw new NullPointerException();
 // callable是一个Callable对象
 this.callable = callable;
 // state记录FutureTask的状态
 this.state = NEW; // ensure visibility of callable
}

#3. FutureTask的run()方法

我們繼續回到submit()的源碼中。
在newTaskFor()新建一個ftask物件之後,會透過execute(ftask)執行該任務。此時ftask被當作一個Runnable物件執行,最終會呼叫到它的run()方法;ftask的run()方法在java/util/concurrent/FutureTask.java中實現,原始碼如下:


public void run() {
 if (state != NEW ||
 !UNSAFE.compareAndSwapObject(this, runnerOffset,
     null, Thread.currentThread()))
 return;
 try {
 // 将callable对象赋值给c。
 Callable<V> c = callable;
 if (c != null && state == NEW) {
  V result;
  boolean ran;
  try {
  // 执行Callable的call()方法,并保存结果到result中。
  result = c.call();
  ran = true;
  } catch (Throwable ex) {
  result = null;
  ran = false;
  setException(ex);
  }
  // 如果运行成功,则将result保存
  if (ran)
  set(result);
 }
 } finally {
 runner = null;
 // 设置“state状态标记”
 int s = state;
 if (s >= INTERRUPTING)
  handlePossibleCancellationInterrupt(s);
 }
}

說明:run()中會執行Callable物件的call()方法,並且最終將結果儲存到result中,並透過set(result)將result保存。
      之後呼叫FutureTask的get()方法,回傳的就是透過set(result)儲存的值。

以上是Java concurrency執行緒池之關於Callable和Future的程式碼詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn