2

I am trying to convert some serial code into some 'nice' multithreaded code, but when I try to run it, I get a java.util.ConcurrentModificationException of the iterator from the point I get more than 200 elements in the Set I'm iterating over. I thought you could only get this exception if you tried modifying something you're trying to acces/iterate over or vice versa, but I am not changing anything.

The example I'm talking about iterates over the keySet of a TreeMap and the code looks as follows:

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;
}

with the calling method looking like:

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;
}

Could anybody tell me why I get the exception and what I could do to solve this problem? Preferably without having to use ConcurrentSkipListMap or having to change anything in the signature.

Thanks in advance


Edit: completed code and added the calling method as well

  • 1
    What is `S1`? Please paste the full code – fge Apr 18 '15 at 20:28
  • Possible solution: use a copy of the map in run() (e.g. ImmutableMap.copyOf(S)). – ZhekaKozlov Apr 18 '15 at 20:28
  • 1
    This will probably not solve your problem, but you can use an `ExecutorCompletionService` to track all submitted `Future` objects to that you don't have to maintain an array by your own. – isnot2bad Apr 18 '15 at 20:32
  • 3
    I'm pretty sure that the issue hides in parts of the code that you didn't post. Maybe you're calling another method that modifies `S` ? – Nir Alfasi Apr 18 '15 at 20:36

1 Answers1

3

According to the Java specification, get(..) should not throw a ConcurrentModificationException if the SortedMap has not been structurally modified. As you have not provided the full code, the only thing I can suggest is to wrap the SortedMap with Collections.unmodifiableSortedMap(S s) after you create it. This will throw an Exception if you have missed code that structurally modifies the Map.

Even if the code you provided does not modify the SortedMap, this doesn't exclude that an external(out of method)thread does not modify it.

Ioannis Deligiannis
  • 2,679
  • 5
  • 25
  • 48
  • The wrapper works, but would you coincidentally know where the exception might be coming from, provided the add-ons to the code? – Mr Tsjolder from codidact Apr 19 '15 at 08:39
  • If the wrapper works, this means that you are modifying the `SortedMap` outside of this method. Try wrapping it earlier at the point where you don't expect any more updates to flush out the thread that modifies it. It is always a good idea to use read-only structures in multi-threaded applications unless you use thread-safe structures. – Ioannis Deligiannis Apr 19 '15 at 08:56
  • I could move it all the way up to the initialisation of `reS` (after `Storage.store` of course) in `equivalenceClasses(...)` and even delete it again after having changed the initialisation of `reS` to be `reS = new SortedMap[till+1]` instead of `new TreeMap[till+1]`. Explanation is still welcome... – Mr Tsjolder from codidact Apr 19 '15 at 09:53