2015-04-18 31 views
2

我想將一些串行代碼轉換成一些'很好'的多線程代碼,但是當我嘗試運行它時,我從迭代器的java.util.ConcurrentModificationException獲得了我正在迭代的Set中的200多個元素。我認爲如果你嘗試修改你想要訪問/迭代的東西,反之亦然,你只能得到這個異常,但我沒有改變任何東西。即使我不編輯任何東西,爲什麼會得到ConcurrentModificationException?

的例子我談論遍歷一個TreeMapkeySet和代碼如下:

private static SortedMap<BigInteger,Long> algorithm7(int n, 
     final SortedMap<BigInteger, Long> S, ExecutorService pool) { 

    final SortedMap<BigInteger,Long> S1 = new TreeMap<BigInteger, Long>(); 
    final SmallAntiChain alfa = SmallAntiChain.universeAntiChain(n); 
    final SmallAntiChain u = SmallAntiChain.universeAntiChain(n+1); 
    final SmallAntiChain l = SmallAntiChain.singletonAntiChain(n+1); 

    Future<?>[] list = new Future[S.size()]; 
    int i = 0; 
    for (final BigInteger tCode : S.keySet()) { 
     list[i++] = pool.submit(new Runnable() { 

      @Override 
      public void run() { 
       SmallAntiChain t = SmallAntiChain.decode(tCode); 
       Set<int[]> rtsymm = (t.join(l)).symmetryGroup(); 
       SortedMap<BigInteger, Long> St = new TreeMap<BigInteger, Long>(); 
       for (SmallAntiChain x : new AntiChainInterval(t.join(l),u.omicron(t, alfa))) { 
        BigInteger b = x.standard(rtsymm).encode(); 
        Storage.store(St, b); 
       } 
       for (BigInteger b : St.keySet()) { 
        SmallAntiChain x = SmallAntiChain.decode(b); 
        BigInteger code = x.standard().encode(); 
        Storage.store(S1,code,St.get(b)*S.get(tCode)); 
       } 
      } 

     }); 
    } 

    try { 
     for(Future<?> f : list) 
      f.get(); 
    } catch (InterruptedException | ExecutionException e) { 
     e.printStackTrace(); 
    } 

    return S1; 
} 

與調用方法看起來像:

public static SortedMap<BigInteger, Long>[] equivalenceClasses(int till, ExecutorService... pools) throws SyntaxErrorException { 
    if(pools.length < 1) 
     pools = new ExecutorService[]{ Executors.newFixedThreadPool(1) }; 
    @SuppressWarnings("unchecked") 
    SortedMap<BigInteger, Long>[] reS = new TreeMap[till+1]; 
    reS[0] = new TreeMap<BigInteger,Long>(); 
    Storage.store(reS[0],SmallAntiChain.emptyAntiChain().standard().encode()); 
    Storage.store(reS[0],SmallAntiChain.emptySetAntiChain().standard().encode()); 
    int n = 0; 
    while (n < till) { 
     reS[n+1] = algorithm7(n,reS[n], pools[0]); 
     n++; 
    } 
    return reS; 
} 

有誰告訴我爲什麼我得到了異常,我能做些什麼來解決這個問題?最好不必使用ConcurrentSkipListMap或必須更改簽名中的任何內容。

在此先感謝


編輯:完成的代碼,並添加調用方法以及

+1

什麼是'S1'?請粘貼完整代碼 – fge

+0

可能的解決方案:在run()中使用映射的副本(例如ImmutableMap.copyOf(S))。 – ZhekaKozlov

+1

這可能不會解決你的問題,但是你可以使用'ExecutorCompletionService'來跟蹤所有提交的'Future'對象,因爲你不需要自己維護一個數組。 – isnot2bad

回答

3

根據Java規範,get(..)不應該拋出一個ConcurrentModificationException如果SortedMap一直沒有在結構上已修改。由於您沒有提供完整的代碼,因此我建議的唯一方法是在創建之後將SortedMapCollections.unmodifiableSortedMap(S s)包裝起來。這會拋出一個Exception如果你錯過了代碼結構修改地圖。

即使您提供的代碼未修改SortedMap,也不排除外部(超出方法)線程不會修改它。

+0

包裝工程,但你會巧合地知道異常可能來自哪裏,提供附加代碼? –

+0

如果包裝器正常工作,這意味着您正在修改此方法之外的'SortedMap'。嘗試在更早的時候包裝它,以避免更多的更新刷新修改它的線程。除非使用線程安全結構,否則在多線程應用程序中使用只讀結構總是一個好主意。 –

+0

我可以在'equivalenceClasses(...)'中將'reS'(當然是'Storage.store')初始化,甚至在將'reS'的初始化改爲是'reS = new SortedMap [till + 1]'而不是'new TreeMap [till + 1]'。解釋仍然歡迎... –

相關問題