On synchronization of Boolean constants in Java multithreaded programming

  • 2020-04-01 04:16:20
  • OfStack

Multithreaded concurrency is possible in JAVA through synchronized statements. With synchronized code blocks, the JVM ensures that only one thread can hold a lock on an object at a time. The locking mechanism enables multiple threads to access critical resources safely.
 
The synchronization code is written as follows:
 
Code 1:


Object obj = new Object(); 
... 
synchronized(obj) { 
 //TODO: access critical resources
} 

Multithreading in JAVA is always full of pitfalls. If we use Boolean as the synchronized object, two things might happen:
 
1. If you lock an object, you are actually synchronizing different objects.
 
Code 2:
 


private volatile Boolean isTrue = false; 
 
publich void aMethod() { 
 ... 
 synchronized(isTrue) { 
  isTrue = !isTrue; 
  //TODO: access critical resources
  isTrue = !isTrue; 
 } 
 ... 
} 

  At first glance, the code above is fine, because of the use of synchronized(isTrue) only one thread can access the critical resource at a time, but this is not the case. Because the two constants false and true correspond to two different objects. When the isTrue changes, it is likely that different threads will synchronize different objects. JAVA autoboxing changes false to boolean.false, and true to boolean.true (which also means that changing false to boolean.false here results in the same thing). Write the test code for more than one case as follows:
 
Code 3:
 


public class BooleanTest { 
   
  private volatile Boolean isTrue = Boolean.FALSE; //The same goes for false here
   
  public void aMethod() { 
    for(int i=0;i<10;i++) { 
      Thread t = new Thread() { 
        public void run() { 
          synchronized(isTrue) { 
            isTrue = !isTrue; 
            System.out.println(Thread.currentThread().getName() + " - isTrue=" + isTrue); 
            try{ 
              Double ran = 1000 * Math.random(); 
              Thread.sleep(ran.intValue()); 
            }catch(InterruptedException e) {} 
             
            if(!isTrue) System.out.println(Thread.currentThread().getName() + " - Oh, No!"); 
 
            isTrue = !isTrue; 
          } 
        } 
      }; 
      t.start(); 
    } 
  } 
   
  public static void main(String... args) { 
    BooleanTest bt = new BooleanTest(); 
    bt.aMethod(); 
  } 
} 

  Run the above code and every now and then you'll see "-oh, No!" , indicating that different threads are entering a synchronized code block at the same time.
 
Two. Think of synchronization is different objects, is actually an object.
 
Sometimes we may want to synchronize on more than one object, and if we use a Boolean as the synchronized object, it will most likely result in two synchronized blocks that should not be related using the same object's lock. Here's an example:
 
Code 4:
 


private volatile Boolean aBoolean = Boolean.FALSE; 
 
private volatile Boolean anotherBoolean = false; 
 
public void aMethod() { 
 ... 
 synchronized(aBoolean) { 
  //TODO: access critical resource 1
 } 
 ... 
} 
 
public void anotherMethod() { 
 ... 
 synchronized(anotherBoolean) { 
  //TODO: access critical resource 2
 } 
 ... 
} 

  Suppose that aMethod and anotherMethod were called by two unrelated threads, respectively. But since boolean.false and FALSE point to the same object, access to critical resource 2 May be blocked by critical resource 1 (and vice versa).
 
In both cases, when using a synchronized block, try not to use a Boolean object as the synchronized object, or you may encounter unexpected problems or pitfalls for future code changes.
 
It also shows that any synchronization of constants is risky. If you must synchronize a Boolean, be sure to create a Boolean object with the new operator.


Related articles: