synchronized collection getter - java

IIUC, a Collection that is only ever accessed by a synchronized method should be thread-safe - is that right?
e.g.,
class Foo {
private List<String> mList = new LinkedList<>();
public synchronized List<String> getList() {
return mList;
}
}
Assuming this getter is used exclusively to access the list - all operations are via getList() - it feels like it should be thread safe to me - but I'm very happy to be told I'm wrong.
TYIA

This would most likely not suffice as it simply returns a reference of the List; multiple threads would still be able to modify it concurrently, resulting in race conditions. If you're looking for a fully synchronized List, then I suggest using an ArrayList wrapped with Collections#synchronizedList.

Better you go for CopyOnWriteArrayList if you have much more reads than writes, Because its Synchronized and also the Iterator of CopyOnWriteArrayList is Fail-Safe and doesn't throw ConcurrentModificationException.
You can also make the existing list synchronized using Collections.synchronizedList(list) but the Iterator will be Fail-Fast.

Related

ConcurrentModificationException on ArrayList

I'm getting an java.util.ConcurrentModificationException.
The related code is:
for (Iterator<Audit> it = this.pendingAudits.iterator(); it.hasNext();) {
// Do something
it.remove();
}
When it.remove() is called it throws me this exception.
This code is inside an #Serviceannotated class:
#Service
public class AuditService {
public AuditService(
this.pendingAudits = new ArrayList<Audit>();
}
public void flush(Audit... audits) {
this.pendingAudits.addAll(Arrays.asList(audits));
try {
for (Iterator<Audit> it = this.pendingAudits.iterator(); it.hasNext();) {
// Do something
it.remove();
}
}
}
}
The problem appears when two requests reach the code.
How could I avoid this concurrent access exception?
First things first, this is not a Spring-related problem. It's just a problem with a concurrent modification of one not-so-concurrent-friendly ArrayList class.
The simplest solution possible would be to synchronize access to the method that modifies it.
public synchronized void flush(Audit... audits) { }
Keep in mind that it will enforce the sequential execution of the flush method which imposes a huge performance penalty.
Sidenote, it's not enough to synchronize the collection itself by using Collections.synchronizedList - iterator instances returned by synchronized wrappers require manual synchronization.
Isn't it obvious? You are sharing data without proper synchronization.
#Service annotated class generally is a singleton scope class and hence the same instance will be shared among all calling threads.
This results into all threads accessing the flush method on the same instance.
And guess what?
Your flush method is trying to modify an ArrayList which is a member variable. This makes it unsafe in a multithreaded scenario.
It's a good time to revisit the documentation of ArrayList which tells a lot more things about it's iterator.
Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list. If no such object exists, the list should be "wrapped" using the Collections.synchronizedList method. This is best done at creation time, to prevent accidental unsynchronized access to the list:
List list = Collections.synchronizedList(new ArrayList(...));
The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
I think you probably put Audit into the list pendingAudits somewhere and you want to flush them all when you call the flush(Audit...) method, you can use ConcurrentLinkedQueue instead of ArrayList.
public AuditService(
this.pendingAudits = new ConcurrentLinkedQueue<Audit>();
}
public void flush(Audit... audits) {
this.pendingAudits.addAll(Arrays.asList(audits));
try {
Audit audit;
while ((audit = this.pendingAudits.poll) != null) {
// Do something
}
}
}

Correct working with Collections.synchronizedList

I am not sure how to properly use the Collections.synchronizedList() implementation.
I have these two:
public synchronized static List<CurrencyBox> getOrderList() {
return Collections.synchronizedList(orderList);
}
and
public static List<CurrencyBox> getOrderList() {
return Collections.synchronizedList(orderList);
}
So as far as I understood, synchronizedList really returns the orderList and not a copy, correct?
So If I want to gurantee atomic operations, like add and remove, which of the implementation above is correct?
And does something maybe changes with Java9? Or is it still the way to go or have you any other suggestion?
Thank you
Without context it's a bit hard to tell, from the snippets provided neither give you guaranteed atomic operations.
The documentation states:
Returns a synchronized (thread-safe) list backed by the specified
list. In order to guarantee serial access, it is critical that all
access to the backing list is accomplished through the returned list.
So even if you synchronize the method the best you'll get is a guarantee that no two objects are creating the synchronized list at the same time.
You need to wrap the original orderList with Collections.synchronizedList to begin with and return the stored result of that each time.
private static List<CurrencyBox> orderList = Collections.synchronizedList(new ArrayList<CurrencyBox>());
public static List<CurrencyBox> getOrderList() {
return orderList
}
A synchronized list only synchronized methods of this list.
It means a thread won't be able to modify the list while another thread is currently running a method from this list. The object is locked while processing method.
As an example, Let's say two threads run addAllon your list, with 2 different lists (A=A1,A2,A3, B=B1,B2,B3) as parameter.
As the method is synchronized, you can be sure those lists won't be merged randomly like A1,B1,A2,A3,B2,B3
You don't decide when a thread handover the process to the other thread so you can either get A1,A2,A3,B1,B2,B3 or B1,B2,B3,A1,A2,A3.
Credit : jhamon

How to replace a non-synchronized concurrent list or array atomically

I have a List read (iterated through) many times and by multiple threads but updated rarely (reads are more than 50,000 times more numerous). EDIT: in fact, an array would suffice in this case, instead of a List.
When the list is updated, it's simply replaced with a different version (there are no add() or remove() calls).
A CopyOnWriteArrayList avoid the disadvantages of a synchronized list but I'm not sure that setting the list to the new value is atomic. I read this question as well.
To show some code. Consider the following as an attribute of a singleton Spring bean.
List<MyObject> myList; //the list read many times and concurrently.
//called by many threads
public void doStuff(){
for (MyObject mo : myList){
//do something
}
}
//called rarely. It's synchronized to prevent concurrent updates
//but my question is about thread-safety with regards to readers
public synchronized void updateList(List<MyObject> newList){ // newList is a CopyOnWriteArrayList<>();
myList = myNewList; //is this following statement executed atomically and thread-safe for readers?
}
Do I need to use a ReadWriteLock for achieve a thread-safe set?
The need for ReadWriteLock depends what you need to achieve.
If you want to ensure that reference is updated atomically you can use AtomicReference (or in your case enough to mark this reference as volatile), however if your goal is that updater thread should wait until all reading threads finish iterating over old list before updating the reference then ReadWriteLock is the way to go.

Why is this code not thread-safe, even when using a synchronized method?

Why is this code not thread-safe even though we are using synchronized method and hence obtaining a lock on Helper object?
class ListHelper <E> {
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
public synchronized boolean putIfAbsent(E x) {
boolean absent = !list.contains(x);
if (absent)
list.add(x);
return absent;
}
}
Because the list is unlocked when contains returns, and then locked again when add is called. Something else could add the same element between the two.
If you mean to only use the list from within the helper object, it should be declared private; if you do this, the code will be thread safe, as long as all manipulations of the list go through methods that are synchronized in the helper object. It's also worth noting that as long as this is the case, you don't need to be using a Collections.synchronizedList as you're providing all necessary synchronization in your own code.
Alternatively, if you want to allow the list to be public, you need to synchronize your access on the list, rather than on your helper object. The following would be thread safe:
class ListHelper <E> {
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
public boolean putIfAbsent(E x) {
synchronized (list) {
boolean absent = !list.contains(x);
if (absent)
list.add(x);
return absent;
}
}
}
The difference is that it is using the same lock as the other methods of the list, rather than a different one.
This code is not thread safe only because list is public.
If the list instance is private, and referenced nowhere else, this code is threadsafe. Else it is not threadsafe as multiple threads could be manipulating the list simultaneously.
If the list is not referenced elsewhere, you need not declare it as a synchronized list through the collections class, as long as all list manipulation occurs through synchronized methods and a reference to that list is never returned to anything.
When you mark a method synchronized, all threads calling that method are synchronized with the object instance said method is defined in. This is why if ListHelper internal list instance is not referenced elsewhere, and all methods are synchronized, your code would be threadsafe.
A major component of thread safety concerns more than only mutual exclusion. It is quite possible to complete an atomic update of an object's state, i.e. to effect a state transition that leaves an object in a valid state with its invariants intact, but to still leave the object vulnerable if its references are still published to untrustworthy or incompletely debugged clients.
In the example you post:
public synchronized boolean putIfAbsent(E x) {
boolean absent = !list.contains(x);
if (absent)
list.add(x);
return absent;
}
The code is thread safe, as W.M. pointed out. But we have no assurances about x itself and where it may have references still held by other code. If such references did exist, another thread can modify corresponding elements in your list, defeating your efforts to guard the invariants of objects in the list.
If you are accepting elements to this list from client code that you don't trust or don't know about, a good practice would be to make a defense copy of x and then add that to your list. Similarly, if you will be returning an object from your list to other client code, making a defensive copy and returning that will help assure that your list remains thread safe.
Moreover, the list should be fully encapsulated in the class. By having it be public, client code anywhere can freely access the elements and make it impossible for you to protect the state of objects in the list.

Collections.synchronizedList and synchronized

List<String> list = Collections.synchronizedList(new ArrayList<String>());
synchronized (list) {
list.add("message");
}
Is the block "synchronized (list){} " really need here ?
You don't need to synchronize as you put in your example. HOWEVER, very important, you need to synchronize around the list when you iterate it (as noted in the Javadoc):
It is imperative that the user manually synchronize on the returned
list when iterating over it:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
It depends on the exact contents of the synchronized block:
If the block performs a single, atomic operation on the list (as in your example), the synchronized is superfluous.
If the block performs multiple operations on the list -- and needs to maintain the lock for the duration of the compound operation -- then the synchronized is not superfluous. One common example of this is iterating over the list.
The underlying code for Collections.synchronizedList add method is:
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
So in your example it is not needed to add synchronisation.
Also Important to note that any methods that use Iterators for example Collections.sort() will also need to be encapsulated inside a synchronized block.
Read this Oracle Doc
It says "It is imperative that the user manually synchronize on the returned list when iterating over it"
Like what has been mentioned by others, the synchronized collections are thread-safe, but the compound actions to these collections are not guaranteed to be thread-safe by default.
According to JCIP, the common compound actions can be
iteration
navigation
put-if-absent
check-then-act
The OP's synchronized code block isn't a compound action, so no difference whether add it or not.
Let's take the example from JCIP and modify it a little to clarify why it's necessary to guard the compound actions with lock.
There are two methods that operate on same collection list that wrapped by Collections.synchronizedList
public Object getLast(List<String> list){
int lastIndex = list.size() - 1;
return list.get(lastIndex);
}
public void deleteLast(List<String> list){
int lastIndex = list.size() - 1;
list.remove(lastIndex);
}
If methods getLast and deleteLast are called at the same time by two different threads, below interleaves may happen and getLast will throw ArrayIndexOutOfBoundsException. Assume current lastIndex is 10.
Thread A (deleteLast) --> remove
Thread B (getLast) --------------------> get
The Thread A remove the element before the get operation in Thread B. Thus, the Thread B still use 10 as the lastIndex to call list.get method, it will lead to concurrent problem.

Categories

Resources