2016-04-16 85 views
4

我在Java中使用自定義類Foo作爲HashMap中的鍵類型。 Foo實例的所有字段都是不可變的(它們被聲明爲final和private,並且僅在構造函數中被賦值)。因此,給定Foo對象的hashCode()也是固定的,爲了優化目的,我正在構造函數中計算它,並簡單地在hashCode()方法中返回該值。Java線程優化

Foo的實例也有一個value()方法,一旦實例化對象就返回一個類似的固定值。目前我也在構造函數中計算它,並在方法中返回它,但hashCode()value()之間存在差異:hashCode()在創建對象後幾乎立即被調用,但value()稍後調用。據我所知,有一個單獨的線程來計算哈希碼只會增加,因爲同步問題的運行時間,但:

  • 這是一個很好的方法來計算value()?它會改善運行時間嗎?
  • 很簡單Threads夠了,還是我需要使用泳池等?

注:這可能看起來像我優化我的程序錯誤的部分,但我已經制作的「正確」的部分,並從所帶來的平均運行時間縮短〜17秒到〜2秒。 編輯:將有5000個以上的對象,這是一個保守的估計。

+0

,這將是奇怪的,因爲'值()'就能夠在一段時間內返回無效值。 – njzk2

+0

@ njzk2這對我的程序來說很好;正如我所說的,'value()'在對象創建後被稱爲很長時間。 – shardulc

回答

2

這聽起來像延期計算是一個很好的方法 - 是的,如果你創建了很多這些對象,線程池是要走的路。

至於value()的返回值,直到它準備好了,我就從返回無效值望而卻步,而是要麼使其阻塞(並添加一些isValueReady()助手),或使其立即返回一個‘未來’ - 一些對象提供那些相同的isReady和阻止get方法。

此外,永遠不要依賴「太晚」 - 在使用它之前,一定要確保它的值已經準備好。

+0

從理論上講,你的回答聽起來對我來說是正確的,但在實踐中,出現了一些問題:程序運行時間比平時多5倍。我應該提供哪些細節以使我的情況更具體? – shardulc

+0

@shardulc有很多可能的變量,我不知道你的應用程序。我首先會看兩件事:1.計算'value()'有多重?如果創建一個線程池線程更重,它永遠不值得。 2.如何CPU餓死你的應用程序?如果它具有100%的CPU利用率,則推遲計算將不會帶來任何好處,並且您仍然會支付開銷。誠實地說,它可能完全是其他的東西......當代碼不明顯或調試爲什麼有些緩慢時,我依靠分析。 – Oak

1

我建議創建一個Futurevalue - 在其上創建一個靜態fixedTheadPoolsubmitvalue計算。這樣沒有風險value將它可用之前訪問 - 最壞的情況是,無論是訪問value將阻止在Future.get電話(或use the version with a timeout,例如如果僵局是一個問題)

因爲Future.get拋出checked異常從而可以造成滋擾,你可以用你的類的getter方法get呼叫並在概念和架構方面的包裹檢查的異常在RuntimeException

class MyClass { 
    private static final ExecutorService executor = Executors.newFixedThreadPool(/* some value that makes sense */); 

    private final Future<Value> future; 

    public MyClass() { 
     future = executor.submit(/* Callable */); 
    } 

    public boolean isValueDone() { 
     return future.isDone(); 
    } 

    public Value value() { 
     try { 
      return future.get(); 
     } catch(InterruptedException|ExecutionException e) { 
      throw new RuntimeException(e); 
     } 
    } 
}