Java synchronized block and the visibility guarantees for an explicit lock

Viewed 87

I have a class, in which I have a state that consists of several fields-collections.

Now, I have methods that change that state. And there are methods that are reading it.

I want to use an explicit lock to guard state change modifications.

class Sample {
  private final Map<String> a = new HashMap<>();
  private final Map<String> b = new HashMap<>();
  private final Map<String> c = new HashMap<>();

  // protects the state of variables a,b,c so that the state modifications are atomic
  private final Object lock = new Object();

  ...
  // other fields

  private void changeState(StateChange obj){
     synchronized(lock){
         changeA();
         changeB();
         changeC();
    }
  }

  private State readState(){
     synchronized(lock){
         return buildStateFromABC();
    }
  }

}

If this class is accessed/modified in a multi-threaded environment, will each thread see up-to-date contents of fields a,b,c after entering a guarded area?

There is no direct correlation between the lock and those fields, or is there something?

I know that I can use an intrinsic lock here and just slap synchronized on methods, but I want to minimize the protected area.

What would be the preferred way of synchronizing here? On explicit lock object or on this?

1 Answers

When in doubt, there is the JLS, see here:

An unlock on a monitor happens-before every subsequent lock on that monitor.

So your methods readState and changeState (because they use the same lock), will create that happens-before edge, needed for proper visibility.

There is also this part in the JLS that says:

If a program is correctly synchronized, then all executions of the program will appear to be sequentially consistent (§17.4.3).

Followed by :

This is an extremely strong guarantee for programmers. Programmers do not need to reason about reorderings to determine that their code contains data races. Therefore they do not need to reason about reorderings when determining whether their code is correctly synchronized. Once the determination that the code is correctly synchronized is made, the programmer does not need to worry that reorderings will affect his or her code.

So if you understand how the happens before connections happens (according to the JLS guarantees), your code is thread safe.


As to which to favor, a synchronized method or an explicit lock (I would still suggest a ReentrantLock in your case), may be this read can help a bit.

Related