2008-09-26 68 views
378

什麼是設計在Java中的併發線程時使用了Runnable和可調用的接口,你爲什麼會選擇一個比其他的區別?在Java中了Runnable和可調用接口之間的差異

+2

有關更多的討論,請閱讀此頁後,請參閱[應該可優先於Runnable嗎?](http://stackoverflow.com/q/16757142/1005481) – 2013-06-18 08:04:00

回答

357

見解釋here

可調用接口類似於 可運行狀態,在這兩個被設計爲 一個其實例是 潛在地由另一個 線程執行。 一個Runnable,但不 返回結果並不能拋出 檢查異常。

31

我發現這在另一個博客,可以解釋它一點點這些differences

雖然兩個接口是由誰希望在不同的線程執行的執行類實現,但有是它們是在兩個接口之間幾點不同:

  • Callable<V>實例返回V類型的結果,而Runnable實例沒有。
  • 一個Callable<V>情況下可能會拋出檢查異常,而Runnable實例不能

的Java的設計者認爲有必要延長Runnable接口的能力,但他們不希望影響的用途在Runnable接口和可能的,這是爲什麼他們就具有Java 1.5中一個名爲Callable不是改變現有Runnable一個單獨的接口的原因。

223

RunnableCallable的應用有什麼區別。僅與Callable中的返回參數有什麼不同?

基本上是這樣。請參閱this question的答案。和javadoc for Callable

如果Callable可以完成Runnable所做的所有工作,那麼有什麼需要?

因爲Runnable接口不能盡一切Callable呢!

Runnable自Java 1.0以來一直存在,但僅在Java 1.5中引入了Callable ...才能處理Runnable不支持的用例。從理論上講,Java團隊可能已經改變了Runnable.run()方法的簽名,但是這將會破壞二進制兼容性與預1.5代碼,遷移舊Java代碼到新的JVM時,需要重新編碼。這是一個很大的否。 Java努力向後兼容...這是Java商業計算最大的賣點之一。

而且,很明顯,有些用例的任務不需要需要來返回結果或拋出檢查的異常。對於這些用例,使用Runnable比使用Callable<Void>更簡潔,並返回call()方法中的虛擬(null)值。

+4

我想知道您從哪裏獲得此歷史記錄。這非常有用。 – spiderman 2014-05-06 14:36:21

+3

@prash - 基本事實可以在舊教科書中找到。就像Nutshell中的Java第一版一樣。 – 2014-05-29 11:40:37

+1

(@prash - 另外...通過在Java 1.1時代開始使用Java) – 2015-10-23 22:43:23

8

由於這裏已經提到Callable是相對較新的接口,它作爲併發包的一部分被引入。 Callable和Runnable都可以與執行程序一起使用。類Thread(實現Runnable本身)僅支持Runnable。

您仍然可以與執行程序一起使用Runnable。 Callable的優點是您可以將其發送給執行者並立即獲取將來的結果,並在執行完成後進行更新。 Runnable也可以實現,但在這種情況下,您必須自己管理結果。例如,您可以創建結果隊列來保存所有結果。其他線程可以等待這個隊列並處理到達的結果。

63
  • Callable需要實現call()方法而Runnable需要實現run()方法。
  • A Callable可以返回一個值,但Runnable不能。
  • A Callable可以拋出檢查異常,但Runnable不能。
  • A Callable可與ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)方法一起使用,但Runnable不能。

    public interface Runnable { 
        void run(); 
    } 
    
    public interface Callable<V> { 
        V call() throws Exception; 
    } 
    
21

讓我們來看看其中一個會使用Runnable接口和贖回。

Runnable和Callable都在與調用線程不同的線程上運行。但Callable可以返回一個值,Runnable不能。那麼這真的適用於哪裏。

Runnable:如果您有一個消防和遺忘的任務,然後使用Runnable。把你的代碼放入一個Runnable中,當run()方法被調用時,你可以執行你的任務。當你執行你的任務時,調用線程並不在乎。

可調用:如果您嘗試從任務中檢索值,則使用Callable。現在可以自行調用不會完成這項工作。你將需要一個Future,包裝你的Callable,並在future.get()上獲取你的值。這裏調用線程將被阻塞,直到Future返回結果,而結果又等待Callable的call()方法執行。

因此,請考慮一個目標類的接口,您在其中定義了Runnable和Callable包裝方法。調用類將隨機調用不知道哪些是可運行的,哪些是可調用的接口方法。 Runnable方法將異步執行,直到調用Callable方法。這裏調用類的線程會阻塞,因爲您正在從目標類中檢索值。

注意:在目標類中,可以對單個線程執行程序調用Callable和Runnable,使此機制類似於串行調度隊列。所以只要調用者調用了你的Runnable包裝方法,調用線程就可以非常快速地執行而不會阻塞。只要它調用包裝在Future方法中的Callable,它將不得不阻塞,直到執行所有其他排隊的項目。只有這樣方法纔會返回值。這是一個同步機制。

14

Callable接口聲明call()方法,你需要提供仿製藥調用對象的類型()應該返回 - 而另一方面

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

Runnable是接口聲明run()方法,當你創建一個名爲使用runnable進行線程並調用start()。你也可以直接調用run(),但只是執行run()方法是同一個線程。

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

總結幾個顯着的區別是

  1. Callable對象返回的結果的Runnable對象不返回結果。
  2. A Runnable對象不能拋出檢查異常,對象可拋出 異常。
  3. 自Java 1.0以來,Runnable接口一直存在,而在Java 1.5中僅引入了Callable

很少相似之處包括實現Runnable或可調用接口的類

  1. 實例是潛在地由另一個線程執行 。
  2. Callable和Runnable接口的實例可以由ExecutorService通過submit()方法執行。
  3. 兩者都是功能接口,可用於自Java8以來的Lambda表達式。

方法在ExecutorService的接口從Oracle文檔這些接口的

<T> Future<T> submit(Callable<T> task); 
Future<?> submit(Runnable task); 
<T> Future<T> submit(Runnable task, T result); 
10

目的:

Runnable接口應由其實例的類旨在通過Thread執行來實現。該類必須定義一個沒有參數的方法,稱爲run

Callable:返回結果並可能拋出異常的任務。實現者定義了一個沒有參數稱爲call的單一方法。 Callable接口類似於Runnable,因爲它們都是爲其實例可能由另一個線程執行的類設計的。但是,Runnable不會返回結果,也不會拋出檢查的異常。

其他方面的差異:

  1. 你可以通過Runnable創建Thread。但是,您不能通過傳遞Callable作爲參數來創建新線程。您只能將Callable傳遞給ExecutorService實例。

    Example:

    public class HelloRunnable implements Runnable { 
    
        public void run() { 
         System.out.println("Hello from a thread!"); 
        } 
    
        public static void main(String args[]) { 
         (new Thread(new HelloRunnable())).start(); 
        } 
    
    } 
    
  2. 使用Runnable消防和忘記調用。使用Callable來驗證結果。

  3. Callable可以傳遞給invokeAll方法,與Runnable不同。方法invokeAnyinvokeAll執行最常用形式批量執行的,執行任務的一個集合,然後等待至少一個或所有,以完成

  4. 平凡差:要實現的方法名稱=>run()Runnablecall()Callable。可贖回和可運行之間

1

差異是以下:

  1. 可贖回在JDK 5.0中引入但可運行在JDK引入1.0
  2. 可贖回有呼叫()的方法,但可運行已經運行( ) 方法。
  3. Callable調用方法返回值,但Callable運行方法不返回任何值。
  4. 調用方法可以拋出檢查異常,但運行方法不能拋出檢查異常。
  5. 可調用use()方法放入任務隊列,但Runnable使用execute()方法放入任務隊列。
3
+-------------------------------------+--------------------------------------------------------------------------------------------------+ 
|    Runnable    |           Callable<T>           | 
+-------------------------------------+--------------------------------------------------------------------------------------------------+ 
| Introduced in Java 1.0 of java.lang | Introduced in Java 1.5 of java.util.concurrent library           | 
| Runnable cannot be parametrized  | Callable is a parametrized type whose type parameter indicates the return type of its run method | 
| Runnable has run() method   | Callable has call() method                  | 
| Runnable.run() returns void   | Callable.call() returns a value of Type T              | 
| Can not throw Checked Exceptions | Can throw Checked Exceptions                  | 
+-------------------------------------+--------------------------------------------------------------------------------------------------+ 

的Java的設計者認爲有必要延長Runnable接口的能力,但他們不希望影響Runnable接口的用途,可能這就是爲什麼他們去了有原因在Java 1.5中名爲Callable的獨立接口,而不是改變已存在的Runnable接口,該接口自Java 1.0以來就已成爲Java的一部分。 source