I am not able to understand the reason why we should "never synchronize on Boolean"
You should always synchronize
on a constant object instance. If you synchronized on any object that you are assigning (i.e. changing the object to a new object) then it is not constant and different threads will be synchronizing on different object instances. Because they are synchronizing on different object instances, multiple threads will be entering the protected block at the same time and race conditions will happen. This is the same answer for synchronizing on Long
, Integer
, etc..
// this is not final so it might reference different objects
Boolean isOn = true;
...
synchronized (isOn) {
if (isOn) {
// this changes the synchronized object isOn to another object
// so another thread can then enter the synchronized with this thread
isOn = false;
To make matters worse, any Boolean
that is created through autoboxing (isOn = true
) is the same object as Boolean.TRUE
(or .FALSE
) which is a singleton in the ClassLoader
across all objects. Your lock object should be local to the class it is used in otherwise you will be locking on the same singleton object that other classes might be locking on in other lock cases if they are making the same mistake.
The proper pattern if you need to lock around a boolean is to define a private final
lock object:
private final Object lock = new Object();
...
synchronized (lock) {
...
Or you should also consider using the AtomicBoolean
object which means you may not have to synchronize
on it at all.
private final AtomicBoolean isOn = new AtomicBoolean(false);
...
// if it is set to false then set it to true, no synchronization needed
if (isOn.compareAndSet(false, true)) {
statusMessage = "I'm now on";
} else {
// it was already on
statusMessage = "I'm already on";
}
In your case, since it looks like you need to toggle it on/off with threads then you will still need to synchronize
on the lock
object and set the boolean and avoid the test/set race condition:
synchronized (lock) {
if (isOn) {
isOn = false;
statusMessage = "I'm off";
// Do everything else to turn the thing off
} else {
isOn = true;
statusMessage = "I'm on";
// Do everything else to turn the thing on
}
}
Lastly, if you expect the statusMessage
to be accessed from other threads then it should be marked as volatile
unless you will synchronize
during the get as well.
java.lang.Boolean
objects in a running JVM, no matter how many Boolean variables you create. This creates a serious aliasing: everyone synchronized on the same pair objects, while their program makes it look like they synchronize on entirely different instances! – Eclairsynchronized
blocks in your program. Let's say you have ten areas that need mutual exclusion, so you create ten objects on which you synchronize. However, when your objects areBoolean
, all your ten variables will point to only two objects -True
andFalse
, so your program will not work as you intended it to. – Eclairthis
- e.g. nice bug if you also extend a thread instead of using runnable) – Outstretch