2016-09-23 18 views
3

我做SHT,如:當你想發送一個匿名函數時,(Runnable&Serializable)是否太昂貴?

executor.execute((Runnable & Serializable)func); 

凡FUNC是一個匿名函數,我要在項目中大量使用這個,否則我將不得不創建一個類爲每個不同的功能,我想打個電話實現Runnable和序列化在每個類中,優點是我會在編譯時輸入類型而不是在運行時拋出它,我想知道這樣做是否太昂貴或是微不足道的,並不代表一個大的表現差距。

如果你有這方面的實際生活經驗,並且你願意分享它,那將是非常棒的。

在此先感謝。

回答

1

由於它只驗證給定的對象是否擴展了某個類或實現了一個接口 - 它不會改變對象本身,所以Casting「幾乎是微不足道的」。

在你的情況,如果func代表lambda表達式或方法引用

executor.execute((Runnable & Serializable)() -> System.out.println("5")); 
executor.execute((Runnable & Serializable) System.out::println); 

LambdaMetafactory保證生成的拉姆達對象真正實現RunnableSerializable和演員甚至可能得到優化。

然而,如果func是參數傳遞給方法:

public void execute(Runnable func) { 
    executor.execute((Runnable & Serializable)func); 
} 

無論是java編譯器,也不是Java運行時會莫名其妙地神奇地讓func序列化了。

在這種情況下,可以重寫方法

public <T extends Runnable & Serializable> void execute(T func) { 
    executor.execute(func); 
} 

這就要求呼叫者提供一種可運行和序列化對象 - 無論是自動生成的一個(通過lambda表達式或方法引用)或「手動」編碼類。

+1

僅當「func」是實際的lambda表達式或方法引用時,在這種情況下,根本不會有運行時類型轉換。就目前而言,如果'func'只是一個引用已經存在的函數的標識符,這是一個普通的類型轉換,它不會將該函數轉換爲可序列化的類型。 – Holger

+0

@Holger謝謝你的提示。我試圖改進我的回答 –

+1

請注意,在上例中,類型轉換是不必要的。 – Holger

0

在大多數情況下,在運行時執行任何操作最終會導致其編譯時選擇的代價更高。有些情況並非如此,但大多數情況下JVM的表現更好。對於我見過這種實現的大多數情況,這樣做的成本更高。最終它將取決於你將運行的任務數量。如果它們很多,我建議在這裏使用一個接口或抽象。沿着線的東西....

public interface RunnableSerializable extends Runnable, Serializable { 
    // override and add as necessary 
} 

public class MyRunnableClass implementes RunnableSerializable { 
    // your runnable code 
} 

MyRunnableClass clazz = ... 
executor.execute(clazz); 

如果它只是極少數可運行的每幾分鐘(或以上),類型轉換應該罰款。

0

轉換本身非常簡單:它只是一個if-else,它將通過JIT和分支預測器進行優化,因爲您始終都在傳遞有效的類(您沒有看到任何ClassCastException)。

我想這裏真正的問題是,如果執行(通過通過接口通過Runnable.run()進行虛擬調用)匿名lambda或聲明的類之間有任何區別。所以我成立了一個JMH基準測試3以下使用lambda表達式的情況下,宣佈類:

  1. 執行的東西
  2. 執行隨機不同的東西(以防止分支預測如果有的話)
  3. 執行隨機不同的東西,但有些東西會

結果顯示lambda表達式是納秒的事情更慢更經常發生(如果有的話允許分支預測),所以實際上它看起來像labmda或聲明的類都沒有區別:

Benchmark                    Mode  Cnt   Score Error Units 
    MyBenchmark.testAnonymousLambda              sample 7272891  16.150 ± 1.646 ns/op 
    MyBenchmark.testDeclared                sample 7401499  15.349 ± 3.648 ns/op 
    MyBenchmark.testRandomAnonymousLambda             sample 6851255  3314.151 ± 11.655 ns/op 
    MyBenchmark.testRandomBranchingDeclared            sample 6887926  3293.818 ± 9.180 ns/op 
    MyBenchmark.testPredictableAnonymousLambda            sample 3990711  6091.766 ± 25.912 ns/op 
    MyBenchmark.testPredictableBranchingDeclared           sample 3993885  6055.421 ± 21.535 ns/op 

所以在回答你的問題時,如果你要施放,或者如果你會使用lambda而不是創建一組聲明的類,那並不重要。

P.S.基準代碼可通過a gist