2009-12-03 40 views
73

最近我一直在尋找Go's goroutines,並認爲在Java中擁有類似的東西會很好。至於我尋找並行化方法調用的常見方法是做類似的事情:如何在Java中異步調用方法

final String x = "somethingelse"; 
new Thread(new Runnable() { 
      public void run() { 
       x.matches("something");    
    } 
}).start(); 

那不是很優雅。 有沒有更好的方法來做到這一點?我在項目中需要這樣的解決方案,所以我決定圍繞異步方法調用實現自己的包裝類。

我發佈了我的包裝類J-Go。但我不知道這是否是一個好的解決方案。用法很簡單:

SampleClass obj = ... 
FutureResult<Integer> res = ... 
Go go = new Go(obj); 
go.callLater(res, "intReturningMethod", 10);   //10 is a Integer method parameter 
//... Do something else 
//... 
System.out.println("Result: "+res.get());   //Blocks until intReturningMethod returns 

或更簡潔:

Go.with(obj).callLater("myRandomMethod"); 
//... Go away 
if (Go.lastResult().isReady())    //Blocks until myRandomMethod has ended 
    System.out.println("Method is finished!"); 

內部我使用實現Runnable的類,做一些反思工作,以得到正確的方法對象,並調用它。

我想要一些關於我的小型庫和關於在Java中使用這種異步方法調用的主題的看法。它安全嗎?有沒有更簡單的方法?

+1

你能再次展示你的J-Go lib代碼嗎? – msangel 2013-09-11 19:00:35

+0

我正在研究一個項目,我正在閱讀一個字符明智。一旦完整的單詞被讀取,我正在對該單詞執行許多操作。最後我把它放入一個集合中。一旦讀取了流中的所有數據,我就返回響應。每次我對一個單詞進行操作時,我決定啓動線程。但它降低了整體表現。然後我知道線程本身是一個昂貴的操作。我不確定是否啓動一個線程同時調用一個方法可以提供任何性能增加,直到它執行任何繁重的IO操作。 – 2016-04-03 12:59:21

+0

偉大的問題! Java 8爲此提供了CompletableFutures。其他答案是基於Java的老版本 – Programmer 2017-09-12 18:57:55

回答

25

你也不妨考慮類java.util.concurrent.FutureTask

如果您使用的是Java 5或更高版本,則FutureTask是「可取消的異步計算」的交鑰匙實現。

java.util.concurrent包中有更豐富的異步執行調度行爲(例如,ScheduledExecutorService),但FutureTask可能具有您需要的所有功能。

我甚至會說自從FutureTask變得可用以後,不再推薦使用第一種代碼模式作爲示例。 (假設你使用的是Java 5或更高版本。)

+0

事情是我只想執行一個方法調用。這樣我就不得不改變目標類的實現。我想要的是完全調用,而不必擔心Impnementing Runnable或Callable – 2009-12-04 02:45:43

+0

我聽到你的聲音。 Java尚未具備一流的功能,因此這是目前最先進的技術。 – shadit 2009-12-04 05:11:01

+0

感謝「未來」關鍵字......現在我正在打開關於它們的教程......非常有用。 :D – gumuruh 2012-06-07 08:50:48

16

我不喜歡使用Reflection的想法。
不僅在一些重構中丟失它是很危險的,但它也可以被SecurityManager拒絕。

FutureTask作爲java.util.concurrent包中的其他選項是一個不錯的選擇。
我簡單的任務最喜歡的:

Executors.newSingleThreadExecutor().submit(task); 

位不是創建一個線程(任務是可贖回或一個Runnable)

+1

事情是我只想執行一個方法調用。這樣我就不得不改變目標類的實現。我想要的東西是正確的調用,而不必擔心暗示Runnable或Callable – 2009-12-04 02:44:57

+0

然後這將不會幫助很多:(但*通常*我寧願使用Runnable或Callable而不是反射 – 2009-12-04 12:43:13

+3

只是一個簡短的說明:這是更好跟蹤'ExecutorService'實例,所以你可以在必要時調用'shutdown()'。 – 2012-06-12 09:36:59

7

您可以使用@Async註釋從jcabi-aspects和AspectJ短:

public class Foo { 
    @Async 
    public void save() { 
    // to be executed in the background 
    } 
} 

當你調用save()時,一個新的線程啓動並執行它的主體。您的主線程不會等待save()的結果。

+0

請注意,這種方法會使所有調用保存異步,這可能是我們想要的,也可能不是我們想要的。一個給定的方法應該是異步的,可以使用此頁面上建議的其他方法。 – bmorin 2015-10-22 12:19:59

+0

我可以在Web應用程序中使用它嗎(因爲不建議管理線程 那裏) ? – onlinenaman 2017-07-05 15:12:39

90

我才發現,原來有做一個更清潔的方式您

new Thread(new Runnable() { 
    public void run() { 
     //Do whatever 
    } 
}).start(); 

(至少在Java中8),你可以使用lambda表達式來縮短到:

new Thread(() -> { 
    //Do whatever 
}).start(); 

由於簡單的做在JS中的功能!

+0

你的答案幫助了我的問題 - http://stackoverflow.com/questions/27009448/prevent-client-repeatedly-sending-requests。應用我的情況有點棘手,但最終解決了:) – Deckard 2014-11-19 06:56:39

+0

如何使用參數調用? – yatanadam 2016-12-29 22:04:08

+1

@yatanadam這可能會回答你的問題。只需將上面的代碼放置在方法中,並像通常那樣將變量傳遞給變量。看看我爲你製作的[測試代碼](https://pastebin.com/8f1Tmscy)。 – user3004449 2017-04-12 07:00:44

2

這並沒有真正相關,但如果我要異步調用方法,例如比賽(),我會用:

private final static ExecutorService service = Executors.newFixedThreadPool(10); 
public static Future<Boolean> matches(final String x, final String y) { 
    return service.submit(new Callable<Boolean>() { 

     @Override 
     public Boolean call() throws Exception { 
      return x.matches(y); 
     } 

    }); 
} 

然後調用異步方法,我會用:

String x = "somethingelse"; 
try { 
    System.out.println("Matches: "+matches(x, "something").get()); 
} catch (InterruptedException e) { 
    e.printStackTrace(); 
} catch (ExecutionException e) { 
    e.printStackTrace(); 
} 

我測試了這一點,它的工作原理。只是認爲它可以幫助別人,如果他們只是爲了「異步方法」而來。

5

您可以使用Future-AsyncResult進行此操作。

@Async 
public Future<Page> findPage(String page) throws InterruptedException { 
    System.out.println("Looking up " + page); 
    Page results = restTemplate.getForObject("http://graph.facebook.com/" + page, Page.class); 
    Thread.sleep(1000L); 
    return new AsyncResult<Page>(results); 
} 

參考:https://spring.io/guides/gs/async-method/

+4

如果您正在使用彈簧引導。 – 2015-10-22 13:27:09

2

它可能不是一個真正的解決方案,但現在 - 在Java中8 - 你至少可以更好一點使用lambda表達式使此代碼的樣子。

final String x = "somethingelse"; 
new Thread(() -> { 
     x.matches("something");    
    } 
).start(); 

而且你甚至可以在一行中做到這一點,仍然有它的可讀性。

new Thread(() -> x.matches("something")).start(); 
+0

使用Java 8真的很好。 – Mukti 2016-09-09 14:02:16

2

您可以使用AsyncFuncCactoos

boolean matches = new AsyncFunc(
    x -> x.matches("something") 
).apply("The text").get(); 

它會在後臺執行,結果將在get()可作爲一個Future

5

您可以對CompletableFuture使用Java8語法,這樣您可以根據調用異步函數的結果執行其他異步計算。

例如:

CompletableFuture.supplyAsync(this::findSomeData) 
        .thenApply(this:: intReturningMethod) 
        .thenAccept(this::notify); 

更多細節可以在包java.util.concurrent.CompletableFuture可用此article

1

的Java 8中引入CompletableFuture發現,可以用來進行非同步呼叫:

CompletableFuture.runAsync(() -> { 
    // method call or code to be asynch. 
}); 
+0

'CompletableFuture'在另一個答案中被提到,但是那個人使用了整個'supplyAsync(...)'鏈。這是一個完美適合問題的簡單包裝。 – ndm13 2018-02-05 15:20:12