java中存在Runnable、Callable、Future、FutureTask這幾個與線程相關的類或者接口,在Java中也是比較重要的幾個概念,我們通過下面的簡單示例來了解一下它們的作用于區別。Runnable
其中Runnable應該是我們最熟悉的接口,它只有一個run()函數,用于將耗時操作寫在其中,該函數沒有返回值。然后使用某個線程去執行該runnable即可實現多線程,Thread類在調用start()函數后就是執行的是Runnable的run()函數。Runnable的聲明如下 :
[java] view plain copy
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> * * @see java.lang.Thread#run() */ public abstract void run(); } ![]()
Callable
Callable與Runnable的功能大致相似,Callable中有一個call()函數,但是call()函數有返回值,而Runnable的run()函數不能將結果返回給客戶程序。Callable的聲明如下 :
[java] view plain copy
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; }
可以看到,這是一個泛型接口,call()函數返回的類型就是客戶程序傳遞進來的V類型。Future
Executor就是Runnable和Callable的調度容器,Future就是對于具體的Runnable或者Callable任務的執行結果進行
取消、查詢是否完成、獲取結果、設置結果操作。get方法會阻塞,直到任務返回結果(Future簡介)。Future聲明如下 :
[java] view plain copy
/** * @see FutureTask * @see Executor * @since 1.5 * @author Doug Lea * @param <V> The result type returned by this Future's <tt>get</tt> method */ 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. * */ 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. * */ boolean isDone(); /** * Waits if necessary for the computation to complete, and then * retrieves its result. * * @return the computed 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. * * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument * @return the computed result */ V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } ![]()
FutureTask
FutureTask則是一個RunnableFuture<V>,而RunnableFuture實現了Runnbale又實現了Futrue<V>這兩個接口,
[java] view plain copy
public class FutureTask<V> implements RunnableFuture<V>
RunnableFuture[java] view plain copy
public interface RunnableFuture<V> extends Runnable, Future<V> { /** * Sets this Future to the result of its computation * unless it has been cancelled. */ void run(); } ![]()
另外它還可以包裝Runnable和Callable<V>, 由構造函數注入依賴。
[java] view plain copy
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 }
可以看到,Runnable注入會被Executors.callable()函數轉換為Callable類型,即FutureTask最終都是執行Callable類型的任務。該適配函數的實現如下 :[java] view plain copy
public static <T> Callable<T> callable(Runnable task, T result) { if (task == null) throw new NullPointerException(); return new RunnableAdapter<T>(task, result); }
RunnableAdapter適配器[java] view plain copy
/** * A callable that runs given task and returns given result */ static final class RunnableAdapter<T> implements Callable<T> { final Runnable task; final T result; RunnableAdapter(Runnable task, T result) { this.task = task; this.result = result; } public T call() { task.run(); return result; } } ![]()
由于FutureTask實現了Runnable,因此它既可以通過Thread包裝來直接執行,也可以提交給ExecuteService來執行。
并且還可以直接通過get()函數獲取執行結果,該函數會阻塞,直到結果返回。因此FutureTask既是Future、
Runnable,又是包裝了Callable( 如果是Runnable最終也會被轉換為Callable ), 它是這兩者的合體。
簡單示例
[java] view plain copy
package com.effective.java.concurrent.task; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; /** * * @author mrsimple * */ public class RunnableFutureTask { /** * ExecutorService */ static ExecutorService mExecutor = Executors.newSingleThreadExecutor(); /** * * @param args */ public static void main(String[] args) { runnableDemo(); futureDemo(); } /** * runnable, 無返回值 */ static void runnableDemo() { new Thread(new Runnable() { @Override public void run() { System.out.輸出結果
Thread、Runnable、Callable,其中Runnable實現的是void run()方法,Callable實現的是 V call()方法,并且可以返回執行結果,其中Runnable可以提交給Thread來包裝下,直接啟動一個線程來執行,而Callable則一般都是提交給ExecuteService來執行。