1

I have multiple threads running in a Java application, and all of them need to access the same list. Only one thread, however, actually needs to insert/delete/change the list, and the others just need to access it.

In the other threads, I want to make a copy of the list for me to use whenever I need to read it, but is there any way to do this in a thread safe way? If I had a method to copy the list element by element and the list changed, that would mess it up wouldn't it?

EDIT:

The list will not be deleted from very often, so would it work if I just copied it normally and caught exceptions? If the list grew in the middle of the copy and I missed it, it wouldn't really make a difference to functionality

Jamal H
  • 934
  • 7
  • 23
  • Maybe the [Sync List](https://stackoverflow.com/questions/2444005/how-do-i-make-my-arraylist-thread-safe-another-approach-to-problem-in-java) could be useful – ZeldaZach Jun 23 '17 at 18:50
  • 3
    Instead of making a copy every time all the reading threads need to read the list, it would probably more efficient to make a copy when the single writer changes the list. That's the strategy of CopyOnWriteArrayList. You could also use a ReadWriteLock. – JB Nizet Jun 23 '17 at 18:52
  • I looked up CopyOnWriteArrayList, but the list I'm using will be written to very often so it seems a little inefficient – Jamal H Jun 23 '17 at 18:56
  • Are you sure it would be less efficient to copy the list at each write, rather than to copy it at each read as you're willing to do? – JB Nizet Jun 23 '17 at 18:58
  • Speaking roughly the rate of writes will be about the same as the rate of reads, so I guess it might work. I'll benchmark it and see if it's fast enough. I'm working on a realtime game so speed is important to me. There will also be potentially hundreds of these lists present at once – Jamal H Jun 23 '17 at 19:01

6 Answers6

3

You can use CopyOnWriteArrayList for your purpose.

CopyOnWriteArrayList is a concurrent Collection class introduced in Java 5 Concurrency API along with its popular cousin ConcurrentHashMap in Java.

As name suggest CopyOnWriteArrayList creates copy of underlying ArrayList with every mutation operation e.g. add or set. Normally CopyOnWriteArrayList is very expensive because it involves costly Array copy with every write operation but its very efficient if you have a List where Iteration outnumber mutation e.g. you mostly need to iterate the ArrayList and don't modify it too often.

With this collection, you shouldn't create a new instance every time. You should have only one object of this and it will work.

Mykola Yashchenko
  • 5,103
  • 3
  • 39
  • 48
1

Hmm, so I think that what are you looking for is called CopyOnWriteArrayList.

CopyOnWriteArrayList - A thread-safe variant of ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array.

Ref: CopyOnWriteArrayList

0

You can use CopyOnWriteArrayList which is thread safe ,but it create new one on every update process.

Or you can use readWriteLock so when update use no one can read while multiple thread can read simultaneously .

gati sahu
  • 2,576
  • 2
  • 10
  • 16
0

Depending on your particular usage, you might benefit from one of these:

  1. If you don't really need random access, use ConcurrentLinkedQueue. No explicit synchronization required.
  2. If you don't need random access for writes but only need it for reads, use ConcurrentLinkedQueue for writes and copy it to a list from time to time if changes were made to the queue (in a separate thread), give this list to "readers". Does not require explicit synchronization; gives a "weakly consistent" read view.
  3. Since your writes come from one thread, the previous could work with 2 lists (e.g. the writing thread will copy it to the "reading view" from time to time). However, be aware that if you use an ArrayList implementation and require random access for writes then you are looking at constant copies of memory regions, not good even in the absence of excessive synchronization. This option requires synchronization for the duration of copying.
  4. Use a map instead, ConcurrentHashMap if you don't care about ordering and want O(1) performance or ConcurrentSkipListMap if you do need ordering and are ok with O(logN) performance. No explicit synchronization required.
starikoff
  • 1,601
  • 19
  • 23
0

I decided to solve this by having a separate thread that handles the thread, with BlockingQueue for the other threads to submit to if they want to write to the list, or get from the list. If they wanted to write to the list it would submit an object with the content that they wanted to write, and if they wanted to read, it would submit a Future that the thread with the list would populate

Jamal H
  • 934
  • 7
  • 23
-1
Use Collections.synchronizedList().

Example :

Collections.synchronizedList(new ArrayList<YourClassNameHere>())
Akash
  • 587
  • 5
  • 12
  • That wouldn't change much. You would still need to explicitly synchronize when iterating on the list. – JB Nizet Jun 23 '17 at 18:53