2015-04-16 18 views
0

我有這個容器的Java ConcurrentSkipListMap被陷在某些線程

private ConcurrentMap<Integer,SortedMap<Long,Object>> users; 

它得到的構造users = new ConcurrentHashMap<>();

初始化,併爲每個用戶它得到new ConcurrentSkipListMap<>()

我有這種方法被稱爲過一遍又一遍的線程池

private void process(Object obj){ 
    // SOME CODE 

    SortedMap<Long,Object> q = users.get(obj.userId); 

    logger.debug("SECTION 1"); 

    q.headMap(someNumber).clear(); 

    logger.debug("SECTION 2"); 

    q.put(obj.someId, obj); 

    logger.debug("SECTION 3"); 
} 

這種方法是使用executorService = Executors.newScheduledThreadPool(8);

executorService.execute(new Runnable() { 
      @Override 
      public void run() { 
       process(obj); 
      } 
     }); 

有時它工作正常,但有時(我想在高負載)的一些用戶進程的方法(所有呼叫)卡住,從不輸出部分2

,如果叫我換q.headMap(someNumber).clear();q.put(obj.someId, obj); 它仍然無法輸出部分2

我也試過LinkedBlockingQueue代替ConcurrentSkipListMap但我有同樣的問題

它看起來像死鎖,但我沒有在該結構上使用任何同步語句。

請分享你的想法,如果你有一個

+0

聽起來像一個愚蠢的想法,但是,你確定你的記錄器實例是線程安全的?難道記錄器實際上是造成(潛在的)死鎖?嘗試將每個日誌語句放在同步塊中以便調試,以查看問題是否消失。 – initramfs

+0

它是log4j2。我會嘗試發佈更新 – MySqlError

+0

它是log4j2。第1部分總是得到輸出,並且在「q」後總是被卡住,所以我不認爲這可能是一個問題,但我會試試謝謝 – MySqlError

回答

2

可能有多種原因;最明顯的是代碼不同步。採取線程轉儲來輕鬆識別原因。

的一些問題:

ConcurrentSkipListMap的JavaDoc,它說在headMap()

The returned map will throw an IllegalArgumentException on an attempt to insert a key outside its range. 

所以,如果obj.someId.compareTo(someNumber) < 0您可以將IllegalArgumentExceptionput()這是不處理的任何地方獲得。

而且這可能會導致競爭條件:

q.headMap(someNumber).clear(); 
q.put(obj.someId, obj) 

如果兩個線程都(thread1) someNumber = (thread2) obj.someId你得到一個競爭條件,誰知道會發生下面。而且,JavaDocs說clear()不是原子操作。

而且你沒有提到在您使用users指對象的其他地方;如何填充users

+0

謝謝,但我沒有得到任何例外,所以我們必須假設someNumber是正確的。在線程安全操作中競爭條件會導致死鎖? – MySqlError

+0

@MySqlError沒有看內部的話就很難說。雖然「clear()」不是原子的聲明只是啓發了我的啓示(我必須自己檢查javadoc)。特別是對於SkipListMap,有可能讓一個線程嘗試在半清除的映射上執行put操作,從而導致數據損壞(或可能的死鎖)。 **然而**,你確實說過你嘗試過一個'LinkedBlockingQueue',**有**原子清除,表明你的問題可能在其他地方(如果你選擇使用SkipListMap,你仍然需要修正競爭條件) 。 – initramfs

+1

@MySqlError但你怎麼知道你有死鎖?你有線程轉儲嗎?回答你的問題:我不這麼認爲(我認爲JDK類的構建不夠僵化,但取決於內部實現)。另外你怎麼確定你沒有得到例外?它不會顯示在日誌中,除非你得到'Future'對待它(你的代碼沒有)。看到這裏的更多細節 - http://stackoverflow.com/questions/2248131/handling-exceptions-from-java-executorservice-tasks – m3th0dman

0

它的接縫的問題不在於代碼被卡住,但它拋出一個由theadpool默默處理的例外。我試圖通過日誌記錄啓用自定義的ThreadFactory,但它仍然不起作用。解決方案是爲RuntimeException提供適當的嘗試捕獲s

所以,我學到的教訓是,如果部分代碼沒有在threadpool內部執行,那可能是因爲RuntimeException,你應該提供更多的嘗試捕獲原因

相關問題