简体   繁体   中英

Client-side locking

Following is an excerpt from JCIP

在此处输入图片说明

The author says that in order to make the above code thread-safe we have to use client-side locking.

To make this approach work, we have to use the same lock that the List uses by using client-side locking or external locking. Client-side locking entails guarding client code that uses some object X with the lock X uses to guard its own state. In order to use client-side locking, you must know what lock X uses.

在此处输入图片说明

Why can't we simply make the List< E > object private in the very first place to make the ListHelper class thread-safe?

In that case where each instance of ListHelper would contain its own list you could make that list private and just synchronize on the ListHelper instance. I guess this is a somewhat constructed example to make a point with as little code as possible. IMO the name ListHelper would imply that I could pass an external list which could clearly be reused by multiple ListHelper instances.

I'd say the point is: given the code as it is and without changing visibility of list (could break other code) you better synchronize on list than the current ListHelper instance.

First we should understand the author's purpose. The author's purpose is to construct a thread-safe List tool which is safe for all methods including putifAbsent methods.

And ListHelper may also have some other methods as follows:

public void addList(E x)
{
     list.add(x);
}
public void removeList(E x)
{
     list.remove(x);
}

If some thread invokes the removeList and the second thread invokes the addList and the third invokes the putIfAbsent, then, because they are different locks, error happens.

The point here is to show that if you use synchronized list , and you want to add another thread-safe method you have to use the same lock. the purpose here is to show that if you synchronize in the helper class on this, but rely for the other methods on the synchronization that the list is providing ( lock on the list instance - it will break the thread-safety.

Yes, we can simply make the List< E > object private in the very first place to make the ListHelper class thread-safe. In this way, List< E > object doesn't need to be thread-safe.

class ImprovedList<T> {
    private final List<T> list;

    public ImprovedList(List<T> list) {
        this.list = list;
    }

    public synchronized boolean putIfAbsent(T x) {
        boolean absent = !list.contains(x);
        if (absent)
            list.add(x);
        return absent;
    }
}

If we will make the list private, then how will you utilize other operations of the list other than put-if-absent? Then you will have to implement all other operations of the list as well, so to implement all the list operations you will implement ListHelper with List. Now, you are silently heading towards the composition pattern . Since you implemented your ListHelper with List Interface, so now its not a Helper class anymore, it becomes list itself and thus we can say it is an ImprovedList

class ImprovedList<T> {
    private final List<T> list;

    public ImprovedList(List<T> list) {
        this.list = list;
    }

    public synchronized boolean putIfAbsent(T x) {
        boolean absent = !list.contains(x);
        if (absent)
            list.add(x);
        return absent;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM