2010-03-05 86 views
2

我正在使用第三方庫對7張牌撲克手進行手牌評估。該庫中的方法evaluate被聲明爲公共靜態,我相信它會改變類中的一些全局靜態數組。我遇到的問題是,因爲我正在做一個大約10m枚舉的枚舉算法,所以我要創建FutureTasks,每個評估10m評估的一小部分。我得到的錯誤是:靜態方法被多線程訪問,Java

java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: -2147483648 
    at java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source) 
    at java.util.concurrent.FutureTask.get(Unknown Source) 

從我從谷歌搜索收集哪些試圖檢索中止通過拋出異常的任務的結果時造成的。

是否有某種方法可以使此靜態方法線程安全,就像每個線程正在編輯它自己的全局靜態數組副本一樣?

感謝

+3

我可能會沿着「XX.evaluate()不是線程安全的」的方式打開一個針對庫的增強bug。這是假設圖書館有一些錯誤跟蹤,並積極維護。否則,如果該庫是開源的,你可以自己修復它,並向開發者提供補丁並使用你的補丁版本。 – 2010-03-05 14:23:58

+0

它只發布而不改變它 – Aly 2010-03-05 14:31:05

+2

你確定圖書館沒有試圖保持狀態來記住哪些卡片已被處理/顯示,並使用該信息爲一隻手提供更準確的「價值」? – ptomli 2010-03-05 14:32:43

回答

1

與evaluate方法

​​
2

如果你可以修改代碼,你可以使靜態變量thread local,但它不喜歡你的聲音可以修改這部分代碼。更多關於thread local storage(維基百科)

+0

什麼是線程局部的,它是否具有和使變量和方法非靜態的優點。我這樣說,因爲我可能能夠獲得源代碼 – Aly 2010-03-05 14:11:02

+1

檢查鏈接。線程本地靜態變量是線程本地的靜態變量(即每個線程都有它自己的值,但否則它表現爲靜態)。 – Kris 2010-03-05 14:14:45

+0

@Aly如果你可以獲得源代碼,那麼你只需要在評估方法聲明(以及任何其他可改變受影響靜態的公共訪問方法)中添加'synchronized'關鍵字。 – ptomli 2010-03-05 14:34:18

3

可能加載庫中爲每個線程單獨ClassLoader,以確保每個類都有自己的一套類,因此它自己的一套靜態變量。

但是,如果這樣做,則必須小心以確保這些類加載器的父類加載器無法訪問該庫。

+1

你能提供一個小玩具的例子嗎? – Aly 2010-03-05 14:18:50

+0

另請參見http://java.sun.com/developer/onlineTraining/Security/Fundamentals/magercises/ClassLoader/help.html – trashgod 2010-03-05 15:33:52

0

您是否在安全地操作陣列?你能更好地解釋你的代碼結構嗎?你如何劃分工作以及算法爲什麼需要修改全局數組?

無論如何,也許使用ForkJoin或CyclicBarrier/Phaser來劃分工作會更有意義嗎?

+0

我沒有在數組上操作,我在第三方庫中調用靜態方法在非線程安全的莊園中對陣列進行操作 – Aly 2010-03-05 14:28:59

0

如果你有一個被共享狀態的多線程(全局靜態數組)訪問的方法,你需要確保它們是以線程安全的方式訪問的。

這意味着當您從這些數組中讀取數據時以及寫入數據時,都需要同步/鎖定這兩個數組。

聽起來,只是從你的堆棧跟蹤,你不是。

如果可能,我會建議最小化或消除線程之間共享的狀態量。

0

你不能讓線程安全的,但你可以訪問庫同步:

static Object globalLock = new Object(); 

synchronize (globalLock) { 
    evaluate(); 
} 

這意味着,當然,只有一個線程可以同時執行此方法。所以如果你的程序在這種方法上花費了很多時間,它不會對你有所幫助。

或者,您可以使實例在單獨的進程中運行。但是在流程之間建立溝通(通過RMI或類似)是非常痛苦的。

唯一的其他選擇是重寫它,如果你訪問的源代碼。您必須將所有靜態字段移動到單個上下文類中,然後確保用於訪問靜態字段的所有代碼都具有對新上下文類的實例的引用。

已經提到ThreadLocal機制可以幫助你,因爲它是一種特殊類型的引用,看起來不同於每個線程。這可以使您免於修改方法簽名以將實例傳遞給上下文對象。恕我直言,它可能是清潔的只是將上下文傳遞給方法。有了現代IDE的重構功能,並不難做到。

0

隨着數百萬手的評價,它永遠不會太早看Java Distributed Computing

當您考慮其他good suggestion時,您可以將評估程序包裝在一個簡單的單線程服務器中,並啓動儘可能多的JVM。

最後,考慮寫你自己的評估者;你可以測試你現有的一個,你的可能會更好!