On the problem of extending thread-safe classes in Java

recently read "Java concurrent programming practice," in Section 4.4.1, there is an example: suppose we need a thread-safe List, that needs to provide us with an atomic "put-if-absent" operation. And two implementations are provided:

  1. A non-thread-safe add-as-you-go implementation
public 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;
    }
}
  1. add what you want using client-side locking
public 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;
        }
    }
}

I feel that the translation in the book is rather obscure. I have never understood why the first one is non-thread-safe and the second is thread-safe. Please take a look at what"s going on

.

is probably because the list of public List < E > list = Collections.synchronizedList (new ArrayList < E > ()); is public and can be modified directly.
if more than one thread modifies the list directly.
method 1 locks the putIfAbsent (E x) method, but other threads can still modify the list exposed by public.
for example, when thread A: listHelper.list.add (x) , thread B is just executing boolean absent =! list.contains (x); , it is possible that thread An adds x, but thread B's absent is also judged to be true, and thread B add x again.
method 2 is locked according to list, so only locks that hold list can be judged and added. When thread An is in listHelper.list.add (x) , thread B cannot enter


in the synchronized (list) method. First of all, you should understand that synchronize locks are generally for an object (you can also lock the class). The lock object of the non-thread safe synchronized in
1 is actually the object instantiated by ListHelper < E >, not list,. Other threads can no longer operate on the object instantiated by ListHelper < E >. For this example, the putIfAbsent () method can no longer be used, but the list is public, so you can directly operate on list, such as list.add (), resulting in thread unsafe


.
Collections.synchronizedList(new ArrayList<E>());SynchronizedRandomAccessList

method one synchronized modifies that the method locks the current object
method two returns the same SynchronizedRandomAccessList as the mutex inside the method

Menu