Java – Does client-side locking violate the encapsulation of synchronization policies?

Does client-side locking violate the encapsulation of synchronization policies?… here is a solution to the problem.

Does client-side locking violate the encapsulation of synchronization policies?

For example, Java_author

Client-side locking entails guarding client code that uses some object X with the lock, X uses to guard its own state.


Object X in the following code is list. As mentioned above, using a lock owned by a ListHelper object to synchronize putIfAbsent() is the wrong lock.

package compositeobjects;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ListHelper<E> {

private 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;
        }
    }
}

But, the Java authors say

Client-side locking has a lot in common with class extension—they both couple the behavior of the derived class to the implementation of the base class. Just as extension violates encapsulation of implementation [EJ Item 14], client-side locking violates encapsulation of synchronization policy.

My understanding is that the nested class instances returned by Collections.synchronizedList() also use the locks owned by the list object.


Why does using client-side locking (using list) in ListHelper violate the encapsulation of the sync policy?

Solution

You rely on the fact that synchronizedList uses itself as a monitor, which is exactly what it currently is.

You even rely on syncdList to use synchronized for synchronization, which happens to be true at the moment (this is a reasonable assumption, but it’s not necessary).

There are ways to change the implementation of a synchronizedList, causing your code to not work properly.


For example, the constructor of synchronizedList :

SynchronizedList(List<E> list) {
  super(list);
  // ...
}

Can be changed to

SynchronizedList(List<E> list) {
  super(list, new Object());
  // ...
}

Now, the mutex field used by the method in the SynchronizedList implementation is no longer this (valid), so external synchronization on code>list will no longer work.


That being said, Javadoc describes the fact that using synchronized (list) does have the desired effect. , so this behavior will not be changed, so what you are doing now is absolutely fine; It is designed using leak abstraction, so if you do something similar from scratch, you shouldn’t design it like this, but document the properties of the leak abstraction.

Related Problems and Solutions