2011-09-10 31 views
3

我想出了這個驚人的結果,這是我絕對不知道的原因: 我有被縮短到了兩個方法:同步碼的性能比不同步快一個

private static final ConcurrentHashMap<Double,Boolean> mapBoolean = 
     new ConcurrentHashMap<Double, Boolean>(); 
private static final ConcurrentHashMap<Double,LinkedBlockingQueue<Runnable>> map 
     = new ConcurrentHashMap<Double, LinkedBlockingQueue<Runnable>>(); 


protected static <T> Future<T> execute(final Double id, Callable<T> call){ 
// where id is the ID number of each thread 
synchronized(id) 
{ 
    mapBoolean.get();// then do something with the result 
    map.get();//the do somethign with the result 
} 
} 

protected static <T> Future<T> executeLoosely(final Double id, Callable<T> call){ 

mapBoolean.get();// then do something with the result 
map.get();//the do somethign with the result 

} 

}

在用500多個線程進行分析,每個線程調用上述每個方法400次,我發現execute(..)比executeLoosely(..)執行至少500倍,這是奇怪的,因爲executeLoosely不同步,因此更多線程可以同時處理代碼。

任何原因?

+0

如果您首先介紹第二種方法,該怎麼辦。 – irreputable

回答

4

在我假設的機器上使用500個線程的開銷沒有500個內核,只要在Map上執行查找以執行JVM可以檢測到的代碼就不需要大約100-1000x的任務做任何事情,都可能產生一個隨機的結果。 ;)

你可能遇到的另一個問題是,一個線程執行得更快的測試可以從使用同步中受益,因爲它偏向於訪問一個線程。即它將您的多線程測試恢復爲單線程測試,這是最快速的測試。

您應該比較一下您執行循環的單個線程所獲得的時間。如果這更快(我相信它會),那麼它不是一個有用的多線程測試。

我的猜測是你在非同步代碼之後運行同步代碼。即在JVM稍微升溫之後。交換您執行這些測試的順序並多次運行它們,您將得到不同的結果。

+0

實際上在調用代碼之前,已經發生了很多處理,因此JVM預熱時間被移除。進一步的結果如下: execute:12000 invocations 53.5ms .... executeLoosely:12000 invocations,13000ms ...另外在上面的代碼中,runanble不是tun,它只是添加到從'map – Jatin

+1

如果你看到的不僅僅是2:1的差別,你可能做錯了什麼,但是我看不到你的代碼, –

+0

完全同意彼得在這裏,我會再次檢查測試,因爲你得到的性能差異是不合理的。 – SpaceghostAli

0

在非同步場景中: 1)等待獲取地圖段的鎖定,鎖定,對地圖執行操作,解鎖,等待獲取其他地圖段的鎖定,鎖定,執行操作在另一張地圖上解鎖。 只有在併發寫入段的情況下才會執行段級別鎖定,在您的示例中不會出現這種情況。

在同步方案中: 1)等待鎖定,執行這兩個操作,解鎖。

上下文切換花費的時間會產生影響嗎?運行測試的機器有多少個內核? 地圖結構如何,相同類型的鍵?

+0

'ConcurrentHashMap.get()'在大多數情況下不會獲取段的鎖定。 – axtavt

+0

礦是雙核心機器與2 GB內存。地圖使用與密鑰相同的ID(作爲輸入來執行),最終用於同步塊 – Jatin