Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Synchronizing on an object and changing the reference

Let's say I have an object as follows:

Map<String, String> m = new HashMap<>();

Then I synchronize on this object as follows and change its reference:

synchronize(m){
    m = new HashMap<>();
}

With this code, what happens to the lock on m? Is it still safe to update the new object represented by m? Or is the lock essentially on the old object?

like image 347
gmemon Avatar asked Jan 05 '23 01:01

gmemon


2 Answers

From JLS 17.1:

The synchronized statement (§14.19) computes a reference to an object; it then attempts to perform a lock action on that object's monitor and does not proceed further until the lock action has successfully completed. After the lock action has been performed, the body of the synchronized statement is executed. If execution of the body is ever completed, either normally or abruptly, an unlock action is automatically performed on that same monitor.

Now the questions.

What happens to the lock on m?

Nothing. This is a little bit confusing. Actually, the thread is holding the lock on the object referenced by m at the time it was trying to acquire the lock. The assignment to m in the synchronized block does not automatically "switch" the lock that is being held by the executing thread.

Is it still safe to update the new object represented by m?

It's not safe. The write to m is not synchronized on the same lock.

Or is the lock essentially on the old object?

Yes

like image 74
xiaofeng.li Avatar answered Jan 07 '23 14:01

xiaofeng.li


To safely change reference to the object you can:

  1. Use AtomicReference

    AtomicReference<Map<String, String>>
    
  2. Use synchronized on object which contains this map or better on some other lock object.

    class A {
        private final Object lock = new Object();
        private Map<String, String> m = new HashMap<>();
    
        public void changeMap() {
            synchronized(lock){
                m = new HashMap<>();
            }
        }
    }
    
  3. At least add volatile

    private volatile Map<String, String> m = new HashMap<>();
    

Also see other answers on this topic

  1. Is reference update thread safe?
  2. In Java, is it safe to change a reference to a HashMap read concurrently
like image 23
Nikolay K Avatar answered Jan 07 '23 14:01

Nikolay K