Java - KeyListener thread causes a simultaneous modification. Decision?

My file update cycle is repeated through ArrayList constantly, I also have a KeyListener , which, when clicked, adds an Object to this ArrayList , which seems to throw a parallel modification exception.

After looking back a lot, I decided that it was better to try (I'm pretty new to Java) to figure out a way to combine key events into the main thread. Given this scenario, how can I do this, or is there a way to do this that I don't see? Thanks.

PS: I could learn more complex ways, but I would rather keep it fairly single-threaded and pass key events to the main thread.

+4
source share
3 answers

I assume that you are running an event loop in which you want to add events to the end of the body. If so, you probably want to use a java.util.Queue implementation like LinkedList, and do

 while((event=queue.poll()) != null) { /* process event */ queue.add(keyEvent); } 
+2
source

SOLUTION 1:

Just keep in mind that your listener will be blocked during the iteration process (this also means that your iterator is running on old data, as in solution 2).

If you are using an ArrayList, follow these steps:

 List list = Collections.synchronizedList(new ArrayList()); 

And each time use this list object. You must import

 import java.util.Collections; 

I agree with @msandiford Adding how to iterate ....

 while(some_condition) { do something synchronized(list) { Iterator i = list.iterator(); while (i.hasNext()) do_something_with(i.next()); } do something else } 

This is a quick fix if you have an outer loop in which you iterate. This way, you have not used the synchronized block for some time, so that the KeyListener can be added to the list of arrays.

SOLUTION 2:

If you want to use COW, just keep in mind that whenever an add / update operation occurs, it will make a copy of the collection below and your iterator will not see the change. But the main listener will NOT be blocked (but at this moment a new copy will be created under it).

 import java.util.concurrent.CopyOnWriteArrayList; List list = new CopyOnWriteArrayList<your_object_type>(); 

Iteration:

 while(some_condition) { do something Iterator i = list.iterator(); while (i.hasNext()) do_something_with(i.next()); do something else } 

SOLUTION 3:

This will be a minor design change. This is similar to solution 2, but only makes sense if you are only performing add operations. So what you can do is create another temp list and add it to this list in KeyListener . And as soon as your iteration is done through the synchronized block and move all the objects from temp list to list that you use for iteration. This does NOT block your KeyListener, but the iterator will see the old data, as in solution 2. It can have better performance compared to solution 2.

So, choose a solution that makes sense for your design.

Ref:

Java COW Collections

+2
source

For an event queue, I usually use ConcurrentLinkedQueue , since the queue is great for this model (much better than List / ArrayList).

A queue is much easier to use in streaming form, for example, because there is no "iteration" of the queue in the sense of a list: just click on an element, take an element. Both of these operations can be atomic (and relatively easy to synchronize).

I prefer to approach this model with the assumption / requirement that, as soon as the object consumed from the queue, it can be considered "belonging" to this thread (the thread that places the object must discard the object until it returns the object back through another queue if ever).

ConcurrentLinkedQueue:

Unlimited thread-safe queue based on linked nodes. This queue orders FIFO elements (first-in-first-out) ... ConcurrentLinkedQueue is the appropriate choice when many threads will share access to a common collection [but it works β€œjust fine” for 2] ...

CopyOnWriteArrayList is another structure that can be used, although it is rather a "general" structure. I'm not sure this is β€œfaster,” but given that I have never had a problem with ConcurrentLinkedQueue, this is my first choice for a tripod for the reasons given above. There are also various implementations of concurrency -safe queue, including related queues also found in the concurrent package.

Of course, to stay in the "old school", just synchronize on the same object when 1) modify (or iterate) the collection in EDT (whenever this happens). 2) iteration of the collection in the game stream. This will make the operation mutually exclusive and prevent this exception. One β€œdrawback” is that it can block the user interface thread, depending on how long the loop holds the lock. The same approach can also be used around regular unsynchronized queues.

Happy coding.

+1
source

Source: https://habr.com/ru/post/1382407/


All Articles