1. 程式人生 > >同步調用,異步回調和 Future 模式

同步調用,異步回調和 Future 模式

同步 異步 任務調度 FutureTask

目標

通過與方法的同步調用,異步回調比較,理解 Future 模式

三者的不同

讓我們先來明確一下同步與異步的不同。我們這裏所說的同步和異步,僅局限在方法的同步調用和異步回調中。即,同步指的是調用一個方法,調用方要等待該方法所執行的任務完全執行完畢,然後控制權回到調用方;異步指的是調用一個方法,調用方不等該方法執行的任務完畢就返回,當任務執行完畢時會自動執行調用方傳入的一塊代碼。

同步調用

void runTask {
  doTask1()
  doTask2()
}

同步調用,執行完 doTask1 在執行 doTask2

異步回調

doTask1(new Callback() {
  void call() {
    doTask3()
  }
});
doTask2();

異步回調,會同時執行 doTask1 和 doTask2, 在執行完 doTask1 後執行 doTask3

Future 模式

Future future = doTask1();
doTask2();
doTask3();
Result result = future.get();

我們可以看到,Future 模式中,一個任務的啟動和獲取結果分成了兩部分,啟動執行是異步的,調用後立馬返回,調用者可以繼續做其他的任務,而等到其他任務做完,再獲取Future的結果,此時調用 get 時是同步的,也就是說如果 doTask1 如果還沒有做完,等它做完。

適用情景

我們根據前面的例子可以看出,同步調用適合執行耗時短的任務,異步回調適合執行耗時長的任務,而且調用它之後調用的任務沒什麽關系。

Future 則適合執行長得任務,而且它的結果可能與調用後執行的任務有關系。比如,在燒水的過程中洗刷水壺,最後兩者都完了才能泡茶。

Future模式的 Java 實現

Java 的並發庫實現了 Future 模式,它定義了 Future 接口:

public interface Future<V> {
    boolean cancel(boolean var1);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long var1, TimeUnit var3) throws InterruptedException, ExecutionException, TimeoutException;
}

它未來將會產生我們所需要的結果。

我們通過它取消任務的執行,判斷是否取消和是否完成,獲取結果。

Java 庫還實現了一個 FutureTask, 它實現了 RunnableFuture(它繼承了 Runnable 和 Future)。於是我們就可以用 Executor 來執行這個任務了。

FutureTask<String> futureTask = new FutureTask<>(new Runnable() {
    @Override
    public void run() {

    }
}, "hello");
Executors.newSingleThreadExecutor().execute(futureTask);

... 其他任務

try {
    String result = futureTask.get();
} catch (InterruptedException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
}

總結

  1. 同步調用,調用方掌握控制權
  2. 異步回調,調用方放權,從而可以實現並行處理任務
  3. Future 模式,則是控制權和平行處理的折中

同步調用,異步回調和 Future 模式