2016-06-01 62 views
0

我正在使用ConcurrentSkipListSet集合來處理併發運算符。我發現它有時會卡住,使用此代碼reproduct:使用java時線程卡住ConcurrentSkipListSet添加方法

import java.util.Comparator 
import java.util.concurrent._ 

object SetDeadLock extends App { 
    private val tasks = new ConcurrentSkipListSet[Task](new Comparator[Task](){ 
    override def compare(o1: Task, o2: Task): Int = { 
     val compare = (o1.systemTime - o2.systemTime).toInt 
     if (compare == 0) 1 else compare //distinct same time task 
    } 
    }) 

    for(i <- 1 to 20) { 
    tasks.add(Task()) 
    println(s"added - $i") 
    } 

    case class Task() { 
    val systemTime = System.currentTimeMillis() 
    } 
} 

輸出

added - 1 
added - 2 

這也許停留在別人,除此之外,比較自定義排序數據的方法尤其是他們是一樣的(因爲設置不支持相同的元素),並且所有Task都是新實例,不應與其他人衝突。

jstack CMD,主線程卡住

at java.util.concurrent.ConcurrentSkipListMap.findPredecessor(ConcurrentSkipListMap.java:685) 

確實,這是一個錯誤或我只是誤導一些原則?

謝謝任何​​幫助或建議。

UPDATE
我剛纔試圖修改if (compare == 0) 1 else compareif (compare == 0) -1 else compare,令人驚訝的,我工作得很好!

有沒有人可以澄清它是如何工作的?源代碼對我來說很難(我想很多人都同意我的觀點),畢竟,jdk爲機器執行速度做了很多工作,而不是代碼閱讀器。

最後
爲了避免尷尬的情況只是做出一些不同的因素comparator其匹配Set的語義,如附加一個隨機value.But我認爲它會更好找到另一個真正適合收藏。

幾天前,我發現一個好主意是當systemTime等於時,使用hashCode作爲第二次驗證。希望有幫助〜

+0

可能是如此之快,以至於相同的時間結束,而比較器說相同的時間=不同。不知道它是如何實現的,但我可以想象這會導致一些醜陋的循環,因爲 zapl

+0

@zapl,你是否意味着它是由'Comparator'引起的錯誤?睡500毫米也有問題 – LoranceChen

回答

1

你的比較器不穩定。我不認爲ConcurrentSkipListMap承諾在不同的調用給出不一致的結果時表現得很好。例如,根據您的呼叫方式,您可以同時考慮代碼中的< b和b < a。

+0

我對手段不穩定有些疑惑,換句話說,我應該定義<, >和=?我想存儲具有相同的systemTime元素,正如我們所知,如果比較結果爲0,則add方法將返回false。 – LoranceChen

+0

@LoranceChen - 如果每次詢問時都給出相同的結果,則「穩定」問。在你的情況下,如果'a'和'b'具有相同的'systemTime'值,那麼'a比較b'爲1意味着'a> b'。但'b比較a'是_also_ 1,這意味着'b> a''表示'a

+0

我想我已經知道爲什麼unstable.my當前的解決方案可能也停留在其他java版本。我需要一個真正的可比因子'Set'.Thanks很多。 – LoranceChen