0

I'm doing a cellular automatan that I'm running as an instance of a class with a specific thread provided for it. For the new functionality, namely adding live cells through mouse input while the simulation proceeds , I have to access the class' instance doing the simulation from the main thread, to modify its ArrayList> "world" named 2D container, that my Draw class uses to paint as a reference.

But ArrayList is not threadsafe and I get errors. At this point my "world" of cells is only 50x50, but I'd like to extend its size to 10000^2 or even much bigger. (I'd use quadTrees at that magnitudes)

So my question is, what kind of container should I use, that is both threadsafe, wouldn't take all system resources at higher magnitudes, and "compatible" with the quadTree concept.

I don't know lot about multithreading, should I scrap the idea if of bothering a heavy-weight thread like this or could I maybe pause the thread for the period of evaluating the user's input?(Actually I tried that, I put the thread to sleep and tried to access the instance in the meanwhile, no success.)

I've checked some threadsafe containers, their performance vary depending on if I just iterate over them or edit their properties and such. There are just too many things to consider, I'd really appreciate if someone could show me what direction to pick, Andrew.

Ryan Marv
  • 109
  • 6
  • You should probably explain in more detail which "errors" you receive and what "adding live cells" means (my guess: You are using something like `list.set(i, new LiveCell())` and receive a `ConcurrentModificationException`. Maybe you could just give the cells a *state*, like `cell.isDead()`, this could simplify things...) – Marco13 Aug 14 '14 at 13:56

3 Answers3

1

You could use a concept similar to double buffering. Therefore, have two different planes, let's call them A and B. Every plane represents the entire 'world' of cells. The UI thread is able to draw a plane on screen.

In the first iteration, plane B is updated by reading from plane A. As plane A is only read and not written, and plane B is only written, and not read, this can be done multithreaded without any locks. Just split up the planes into sections and assign every section to a different thread. This could be done dynamically by using the fork/join framework.

When you'r done with the first iteration, hand over plane B to the UI thread. In the meantime, you can start the next iteration, which now reads from plane B into plane A. Again this could be done in parallel.

In general, follow these rules:

  • In every iteration, one plane is read-only, the other one is write-only
  • The UI thread always refers to the read-only plane for redrawing.
  • The cell update threads have seperate, non-overlapping sections for reading and writing.
  • The only synchronization is at the end of every iteration when the planes are switched.

Java has excellent concurrency tools for these things like ForkJoinPool, Exchanger, CyclicBarrier etc.

The write-only plane could maintain one or multiple dirty-regions, so that the UI thread does not have to update the entire UI all the times. But be smart - a dirty-region might be a bottleneck as all threads have to synchronize on it!

isnot2bad
  • 24,105
  • 2
  • 29
  • 50
0

If you have just the two threads, and your automaton thread can be written to relinquish access to critical section periodically, then you might want to consider a re-entrant lock:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html

Its semantics are straightforward and it works best when there are a small number of threads involved.

0xb304
  • 93
  • 7
0

Assuming that the cells themselves are created and added to the matrix only once, during start-up; the problem is not with the ArrayList, but with the cells. This is because reading from an ArrayList is thread safe, regardless of the number of reading threads; what's not thread safe is writing to a cell's fields while another thread is reading them.

In that case, I suggest simply using synchronized methods for the cells themselves, with synchronization on the cell itself. That way, only one thread will be able to access a cell's fields at any one time. There's no need to synchronize each and every method, only those that read and write to fields accessed by both threads.

Malt
  • 28,965
  • 9
  • 65
  • 105
  • If something like this: public synchronized void setCells(int a, int b, boolean c){world.get(a).set(b, c);} resolves that issue with a non-threadsafe container like ArrayList then why would people bother with similar thread-safe containers? – Ryan Marv Aug 14 '14 at 15:15
  • There's a difference between the data structure holding some objects, and those objects themselves. Since the objects are added to the array list exactly once, the array list doesn't change, it's only being read again and again. Therefore there's no problem accessing it with multiple threads. People bother with thread safe collections when the collections themselves are being modified. For example if objects are added and removed from/to the collection by multiple threads while other threads read from it. To my understanding, that's not your case. – Malt Aug 14 '14 at 15:26
  • It is my case, both threads modify the nested ArrayList. Both the simulation, by evaluating the next iteration, and the main thread from user input as new cells are drawn on the grid. – Ryan Marv Aug 14 '14 at 17:01