Synchronizing an ArrayList in a different Class - java

So I'm aware that in order to synchronize an arrayList you need to use
Collections.SynchronizedList(new ArrayList());
But what if the synchronized arrayList is in one class and I want to have a refernce to it in several other classes, the multiple other classes containing the threads that will add to it. Would I do something like
List referenceToList = OtherClass.mainList;
// inside OtherClass would be List<String>mainList
= Collections.sychronizedList(new ArrayList<String>());
Or would the proper way to be
List referenceToList = Collections.synchronizedList(OtherClass.mainList);
Also is there any difference in the way i would iterate over the list, or is it the same as if All the adding and reading was contained in one Class?

It doesn't matter which class the list is contained in - the synchronization is for controlling access to reads and writes to that list from multiple threads (again, regardless of the class it's contained in). Once you've wrapped it in a call to Collections.synchronizedList, there's no point in doing it again.
For clarity (based on your question), your code would look like this:
class OtherClass {
public static List mainList = Collections.synchronizedList(new ArrayList());
}
class RandomClass {
public static List referenceToList = OtherClass.mainList;
}
Here, referenceToList is just a pointer to the same list that mainList points to, which has read/write access synchronized.
As a note, there are other List implementations that are designed for concurrent access situations, such as CopyOnWriteArrayList.

Related

How to synchronize unmodifiable collections

I want to return an unmodifiable view of the class (that maintain a collection of items ) to outside clients .
So to protect concurrent access, I need to wrap the collection in a synchronized wrapper first, then put an unmodifiable wrapper around the version I return to outside threads.
So I wrote the following code and unfortunately it is throwing a ConcurrentModificationException.
.
import java.util.*;
public class Test {
public static void main(String[] args) {
// assume c1 is private, nicely encapsulated in some class
final Collection col1 = Collections.synchronizedCollection(new ArrayList());
// this unmodifiable version is public
final Collection unmodcol1 = Collections.unmodifiableCollection(col1);
col1.add("a");
col1.add("b");
new Thread(new Runnable() {
public void run() {
while (true) {
// no way to synchronize on c1!
for (Iterator it = unmodcol1 .iterator(); it.hasNext(); it.next())
;
}
}
}).start();
while (true) {
col1 .add("c");
col1 .remove("c");
}
}
}
So my question is How to synchronize unmodifiable collections ?
To add more
When a client who received the collection wants to iterate over its elements
1) it doesn't necessarily know that it's a synchronized collection and
2) even if it does, it can't correctly synchronize on the synchronization wrapper mutex to iterate over its elements. The penalty, as described in
Collections.synchronizedCollection, is non-deterministic behaviour.
From my understanding Putting an unmodifiable wrapper on a synchronized collection leaves no access
to the mutex that must be held to iterate correctly.
If you can ensure that read-only clients of the collection synchronize on the collection, synchronize on that same view in your producer:
/* In the producer... */
Collection<Object> collection = new ArrayList<>();
Collection<Object> tmp = Collections.unmodifiableCollection(collection);
Collection<Object> view = Collections.synchronizedCollection(tmp);
synchronized (view) {
collection.add("a");
collection.add("b");
}
/* Give clients access only to "view" ... */
/* Meanwhile, in the client: */
synchronized (view) {
for (Object o : view) {
/* Do something with o */
}
}
You need to decide on a few things first.
A. Are users of the returned collection supposed to automatically see updates to it, and when? If so you would need to take care not to (or decide if this is ok) accidently locking it for updates for periods of time. If using synchronized and synchronizing on the returned collection you are effectively allowing the user of the returned collection to lock it for updates for example.
B. Or should they need to call again to get a fresh collection?
Besides, using Collections.synchronizedX won't give you any protection against iterating over it, just individual read and writes. So would require the client to guarantee that it locks during all explicit and implicit iterations. Sounds bad in general, but depends I guess.
Possible solutions:
Return a copy, don't need to wrap it in unmodifiable even. Just lock it while creating it. synchronized (collection) { return new ArrayList(collection); } No further synchronization needed. An example implementation of Option B above.
Like 1 but automatically by the data structure itself, use CopyOnWriteArrayList and return it (wrapped in unmodifiable). Note: This means writes to the collection are expensive. Reads are not. On the other hand even iterating on it is thread safe. No synchronization whatsoever needed. Supports option A above.
Depending on the properties of the data structure you need you could go for a non RandomAccess list like ConcurrentLinkedQueue or ConcurrentLinkedDeque, both allow iterating etc over the data structure without any extra synchronization. Again, wrapped in unmodifiable. Supports option A above.
I would go for option B-1 for the general case and to get started. But it depends as usual.
You're asking "How to synchronize unmodifiable collections", but actually that's not what you did in your code. You made a syncronized collection unmodifiable. If you 1st make your collection unmodifiable, and then syncronize it, then you'll get what you want.
// you'll need to create the list
final ArrayList list = new ArrayList();
// and add items to it while it's still modifiable:
list.add("a");
list.add("b");
final Collection unmodcol1 = Collections.unmodifiableCollection(list);
final Collection col1 = Collections.synchronizedCollection(unmodcol1);
However the add, remove inside the while will still fail for the same reason.
On the other hand if you created your list and made it unmodifiable, then you might not need to syncronize it at all.
You may want to use one of concurrent collections. That will give you what you need, if I read your question correctly. Just accept to pay on cost.
List<T> myCollection = new CopyOnWriteArrayList<T>();
List<T> clientsCollection = Collections.unmodifiableList(myCollection);
this way, you will not get CME, as client will always get unmodifiable collection and not interfere with your writes. However, price is rather high.

Is it necessary to use synchronizedList instead List if iteration synchronized already?

Task is a simple. I have a dozen threads and one "global" list (of some objects).
Each thread (periodically) iterate through all list to find the desired object and change it (or add it if not present). And then iterate again and save all object to the file.
The JavaDoc says: "It is imperative that the user manually synchronize on the returned list when iterating over it"
And now - all that I do with my list I do inside synchronized block.
Inside implementation of synchronizedList, as I understand, also present some synchronization, and they (I suppose) add undesirable delay.
What if I will use simple List?
I think - if all my doing with the list already in critical section - what I will lose if I change
private static final List<JobSummary> SyncJS = Collections.synchronizedList(new ArrayList<JobSummary>());
to
private static final List<JobSummary> SyncJS = new ArrayList<>();
Or I miss something?
The point of the synchronizedObjects is to avoid manually synchronizing. If you are inside a synchronized block then you don't need them. It will only be extra overhead.
The operation "find the desired object and change it" is not atomic, hence you need to synchronize the list before performing any non atomic actions.
If you synchronize the list for all of your operations, then you do not need Collections.synchronizedList(new ArrayList<JobSummary>()). new ArrayList<>() would work well.

Java: No ArrayList modifications from outside classes

I use an ArrayList in one of my Java project's classes. The class keeps track of whether the list has been changed and offers public methods to add and remove elements from the list that automatically set the variable to "changed".
So far the list is public because I want my list to be publicly readable from everywhere. But I only want the class that owns the list to be able to modify it. So no modifications from outside classes. Is that possible? If so, how?
Usually for access control you'd probably use getter and setter methods. But even with a getter method and the list set to private another class could still do getList().remove(element) and thereby modify the list from the outside without the class noticing that the list was changed.
Make your ArrayList field private, but have your getter return Collections.unmodifiableList(list), which provides an unmodifiable view.
This will allow external code to treat it as a normal List, using for each loops and so on, but will disable modification operations. Additionally, unmodifiableList returns a view in constant time.
This is literally the exact use case it was designed for. Javadoc:
This method allows modules to provide users with "read-only" access to internal lists. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException.
Make your List private and add getter method:
public List getList(){
return new ArrayList(yourPrivateList);
}
You can make the ArrayList member private, and instead of a getter that returns the ArrayList, have a getter that accepts an index i and returns the i'th element of the ArrayList.
public class Test
{
private List<String> list = new ArrayList<String>();
public getString (int i)
{
// you might want to add some validation of i here
return list.get(i);
}
}
getString allows the users of your class to access any element of the list without being able to modify it.
If you want to allow your users to iterate over the list without being able to modify it, you can add a getSize() method to return the size of the list (which would allow the users to iterate over the list using the regular for loop), or your class can implement Iterable (without supporting the remove operation).
You have couple of options here:
The getter that returns the ArrayList can clone before returning the object. This way, even if the outside entity modifies the object, they'll end up modifying the clone - not your original object. Note: The clone operation can be costly. I'd suggest the below option.
Use Collections.unmodifiableList(..). Check the documentation here.
Or as other answers suggest: roll out your own methods for access and iteration.
I think your best option here is to keep your List private and add a getter method that returns a copy of the List, but not the List itself. For example:
public class EncapsulationTest {
private List<Object> privateList = new ArrayList<Object>();
// Your constructors and methods to track list
// modification here ...
public List<Object> getList() {
// Maybe you need a null check here
return new ArrayList<Object>(privateList);
}
public void addElement(Object newElement) {
this.privateList.add(newElement);
// Set your 'changed' variable to true
}
public void removeElement(Object element) {
this.privateList.remove(element);
// Set your 'changed' variable to true
}
}
If you do this, you can still read an exact copy of the List, but you can't modify the List itself. Well, actually you can modify the returned List, but as it is a different object, the changes won't affect your object's List.
I hope it helps.

disable mutability in a Java List

It would be nice to turn objects of Java's List interface into an immutable equivalent at the point in time that mutation is no longer required. That is, the client can call a freeze method that makes the List immutable. The immediate benefit to me is thread-safety without the memory expense of deep copying. (Edit: People would be correct if they assume that one extra immutable copy, to be used by all threads, is affordable.)
Is there a third-party interface or class that provides such a feature?
How about Collections.unmodifiableList(List list)?
There is an ImmutableList class as part of the Guava libraries. You can use the copyOf method to create an ImmutableList from an existing Iterable, eg.
List<String> immutableList = ImmutableList.copyOf(list);
Try to use CopyOnWriteArrayList.
The CopyOnWriteArrayList behaves much like the ArrayList class, except that when the list is
modified, instead of modifying the underlying array, a new array is created and the old array is discarded. This
means that when a caller gets an iterator (i.e. copyOnWriteArrayListRef.iterator() ), which internally
holds a reference to the underlying CopyOnWriteArrayList object’s array, which is immutable and therefore can be
used for traversal without requiring either synchronization on the list copyOnWriteArrayListRef or need to
clone() the copyOnWriteArrayListRef list before traversal (i.e. there is no risk of concurrent modification) and
also offers better performance.
Direct using of Collections.unmodifiableList is not enough if the client still has a reference to the original mutable list.
I would create a delegating list implementation that would have an internal reference to the original mutable list (the delegate) and forward all of the method calls to it. It's a PITA to write such code by hand, but Eclipse for example can generate it automatically for you.
Then upon calling the freeze method, I would wrap the original list with the Collections.unmodifiableList which ensures that all of the future method calls to the FreezingList go to the original delegate only through the unmodifable view.
To make things more secure, but less flexible, you can change the following constructor and instead of passing the original list to it (which can still leave a reference to the original mutable list to the client) instantiate the list internally (for example as an ArrayList).
public class FreezingList<E> implements List<E> {
// the original list you delegate to (the delegate)
private List<E> list;
private boolean frozen = false;
public FreezingList(List<E> list) {
this.list = list;
}
public void freeze() {
if (!frozen) {
list = Collections.unmodifiableList(list);
frozen = true;
}
}
// all the delegating methods follow:
public int size() {
return list.size();
}
public E get(int index) {
return list.get(index);
}
// etc. etc.
}

How to obtain a customized synchronizedList in java?

I have one customized list MyList that extends ArrayList, like this:
class MyList extends ArrayList<SomeParticularItem>{
[some methods...]
}
Since I have concurrent reads and writes to the list, I want to synchronize it:
MyList mylist = (MyList) Collections.synchronizedList(new MyList());
This seems to be fine, the .jar is build. Then, at runtime, I get:
java.util.Collections$SynchronizedRandomAccessList cannot be cast to MyList
Is there a better way (is there any way at all) to obtain a synchronized list of a list that inherits from some java.util.List?
Well why not make MyList synchronized, alternativly simply use the List interface
List mylist = Collections.synchronizedList(new MyList());
Edit:
You could of course let MyList extend Vector, since all of the Vectors methods are already synchronized you save some work.
The easiest way to do it would be to extend Vector instead of ArrayList. You could also synchronize the methods of MyList yourself if you wanted to keep it as an ArrayList.

Categories