-1

Here is my code:

class Processor implements Runnable {

    private int id;
    private Integer interaction;
    private Set<Integer> subset;

    public volatile static AtomicBoolean notRemoved = new AtomicBoolean(true);
    public Object<E> dcp;
    public Iterator<Integer> iterator;



    public Processor(int id, Integer interaction, Set<Integer> subset, Object<E> dcp, Iterator<Integer> iterator) {
        this.id = id;
        this.interaction = interaction;
        this.subset= subset;
        this.dcp = dcp;
        this.iterator = iterator;
    }

    public void run() {
        while (Processor.notRemoved.get()){
            System.out.println("Starting: " + this.id);
            if (this.dcp.PA.contains(this.interaction)){
                this.subset.add(this.interaction);
                this.dcp.increaseScore(this.subset);
                if (!this.subset.contains(this.interaction) && Processor.notRemoved.get()){
                    Processor.notRemoved.set(false);
                    System.out.println(iterator);
                    iterator.remove();
                }
            }

            System.out.println("Completed: " + this.id);
        }
    }
}


public class ConcurrentApp {

    public void multiFunction(Object<E> dcp, int threads) {

        ExecutorService executor = Executors.newFixedThreadPool(threads);

        int i =1;
        while ((dcp.PA.size() > i) && (i <= dcp.R)){
            for (Iterator<Integer> iterator = dcp.PA.iterator(); iterator.hasNext();){
                Integer interaction = iterator.next();
                ArrayList<Integer> removed = new ArrayList<Integer>(dcp.PA);
                removed.remove(interaction);
                ArrayList<Set<Integer>> subsets = dcp.getSubsets(removed, i);
                for (int j = 0; j< subsets.size(); j++){
                    executor.submit(new Processor(j, interaction, subsets.get(j), dcp, iterator));  
                }
                Processor.notRemoved.set(true); //Pretty sure this is necessary
            }
            i++;
        }
        executor.shutdown();
        System.out.println("All tasks submitted");
        try {
            executor.awaitTermination(1, TimeUnit.DAYS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("All tasks completed");
    }
}

As I expected, I am getting java.util.ConcurrentModificationException since multiple threads are trying to simultaneously access my iterator object. I saw a lot of alternatives to using an ArrayList (which is what the field dcp.PA is). I tried using CopyOnWriteArrayList but for some reason I keep getting more problems when I introduce this thread safe implementation of ArrayList. I was wondering if anyone can point me in the right direction as to what thread-safe data structure I should use and how I should use them within my code or other solutions to getting around the concurrent modification error.

g00glechr0me
  • 365
  • 6
  • 19
  • Once again, please do not use `Object` as a name for a custom type. Also, the code you post is not compilable. You don't define `E` there, for example. You don't show the code for `Object`. I can't even fake an `Object` because what the heck is `E` and why doesn't it correlate to the element type of `PA`? It would help if you'd use standard naming conventions. It's really, really hard to advise you when so much of the relevant information is missing from your question. but see my answer anyway. – Lew Bloch Mar 21 '17 at 17:55
  • @LewBloch Sorry for that. I know in a previous post you also told me not to use Object. The reason why I didn't post the code for Object is because I'm fairly confident that the bug is not in that code but in how I am implementing the concurrent portion of my program. Please let me know what information you need and I will provide it to you. I apologize again for being difficult; some of my code is not allowed to be publicly posted so I am doing my best to comply and also give enough info. – g00glechr0me Mar 21 '17 at 18:00
  • Just because you can't share your proprietary code doesn't mean that you should use names like `Object`. Why choose that name, of all the infinite variety of names like `Foo` that you could use? Especially again! Surely you realize that `Object` as a class name holds a special place in Java, right? Right? As for what you hide, you don't hide that there is an element `PA`, or one `dcp`, or a type `E` (terrible name for a type, btw, as it's conventionally for type parameters). So provide us with enough of an implementation for those things. Not that that stopped me from answering. See my answer. – Lew Bloch Mar 21 '17 at 18:17

1 Answers1

2

Maybe it's time to stop asking, "How do I use this particular technique?" and start asking, "How do I accomplish my goal?" Your technique of using an iterator passed in as a parameter is very brittle. And not needed, really.

Resist the temptation to pass iterators around as parameters, let alone to multiple threads. That's a big no-no. You are almost explicitly asking for ConcurrentModificationException. And over what collection does the iterator iterate? There's nothing in your Processor class to enforce coherency. Oh, I know you have the iterator connected to the collection in ConcurrentApp, but the Processor method is public and thus Processor cannot trust in such a connection.

And notRemoved is confusing. What does "removed" even mean? I am also deeply suspicious of its being static when nothing else in your algorithm is.

So the beginning part of your answer is to clean up all the antipatterns in your code. Keep iterators in the same scope as the variables that generate them. Follow the naming conventions. Show all relevant information here if you expect help.

Once you've refactored your code and gotten all the weirdness out, it becomes a lot easier to make removals thread-safe.

void processRemoval(Collection<E> collection) {
  synchronized(lock) {
    for (Iterator<E> iter = collection.iterator(); iter.hasNext(); ) {
      final E element = iter.next();
      if (shouldRemove(element) {
        iter.remove();
      }
    }
  }
}

HTH

Lew Bloch
  • 3,364
  • 1
  • 16
  • 10