Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is client-side locking not generally recommended?

Please explain the following statement about synchronized blocks from "Core Java" by Hortsmann, Cornell (9 ed., p.865):

The get and set methods of the Vector class are synchronized, but that doesn't help us.
...
However, we can hijack the lock:

public void transfer(Vector<Double> accounts, int from, int to, int amount)
{
    synchronized (accounts)
    {
        accounts.set(from, accounts.get(from) - amount);
        accounts.set(to, accounts.get(to) + amount);
    }
    //...
}

This approach works, but it is entirely dependent on the fact that the Vector class uses the intrinsic lock for all of its mutator methods.

Why does the synchronization depend on the mentioned fact? If a Thread A owns the lock on accounts, no other Thread can acquire the same lock. It does not depend on a lock which Vector uses for its mutator methods.

The only possible explanation I was able to think of is the following one. Let Thread A owns lock on accounts. If Vector uses another lock for its set/get, then Thread A must acquire an additional lock to proceed through set/get, and this is impossible for some reason (can a Thread hold 2 different locks at the same time?).

This explanation does not look plausible to me, but I don't have anything else. What am I missing?

like image 604
TT_ Avatar asked Jan 12 '23 13:01

TT_


1 Answers

If a Thread A owns the lock on accounts, no other Thread can acquire the same lock. It does not depend on a lock which Vector uses for its mutator methods.

But if the Vector used a completely unrelated lock for its own synchronization, then your lock object would be pretty meaningless. Code like that would not synchronize:

x.transfer(vector, 100, 100, 100);  // uses your lock

vector.add(100);   // uses Vector's own, unrelated lock

If all your code goes through your own methods (which use your lock), and no one accesses vector's methods directly, then you are fine. (But then you don't need to use Vector's built-in synchronization at all, and could use ArrayList).

These locks only work if all relevant code paths use them. There is usually more than one method involved, and they need to properly "talk to eachother" using the same set of locks. It is up to the programmer to ensure that.

Let Thread A owns lock on accounts. If Vector uses another lock for its set/get, then Thread A must acquire an additional lock to proceed through set/get, and this is impossible for some reason (can a Thread hold 2 different locks at the same time?).

It is not impossible, Thread A can hold any number of locks. However, in the access pattern above, it is pointless for Thread A to hold that first lock, because Thread B won't even try to lock it when it only uses the built-in Vector lock.

like image 75
Thilo Avatar answered Jan 22 '23 12:01

Thilo