Monday, 30 September 2013

Can we synchronize static method/variable in a Java class?


Yes, you can do it.
A synchronized method or block works on a given monitor. Synchronized non-static methods all synchronize on the Java instance of a class. Each instance has a lock monitor. For the case of static methods, what object does static synchronized methods use for locking? The static synchronized statements obtain a lock on the Class object. The following example show you few ways to access the class object:
class MyClass {


    public static void main(String[] args) {
        //you can access class object through an instance of that class
        MyClass objectinstance = new MyClass();
        java.lang.Class myclass1 = objectinstance.getClass();

        //non-instance ways
        java.lang.Class myclass2 = Myclass.class;
 java.lang.Class myclass3 = Class.forName("MyClass");
    }

}
The JVM creates a Class object when the class is loaded (When it is used for the first time). Once a class is loaded into a JVM, the same class will not be loaded again. The JVM creates one instance of Class for each class that is loaded, The Class instances are Objects and can be synchronized via static synchronized methods.
For example
class MyClass  {
  ...
  public synchronized static someMethod() {
    ...
  }
  ...
}
It is the equivalent to the following static synchronized block:
synchronized ( MyClass.class ) {
...
}
In some situatios, you need to protect access static variables, the locking an object instance does not automatically protect access to static variables, because there may have more than one instances and all of them use the same static variables. You have to obtain a lock on the Class vs an instance of the class. A static synchronized block can be use to protect access to static varibales, a lock on a static method has no effect on any instances of that class (see the Java Language Specification). For example,
class BumpTest {

 int count;
 static int classCount;
 void synchronized bump() {
  count++;

  try {
   synchronized (BumpTest.class) { 
                        //or synchronized (Class.forname("BumpTest"))
    classCount++;
   }
  } catch (ClassNotFoundException e) {
 }
    ...
}
Static variables, like static methods, are not inherited, but are accessible from within the body of the class definition and through an explicit reference to the defining class's name. Adding a new static synchronized method in a subclass cannot protect other threads to access static variables defined in its superclass nor should you use synchronized(this.getClass()) which locks the actual Class might be the subclass. An explicit block synchronization with "none-instance way to get Class" is the preferred way.

 synchronized Methods
A synchronized method acquires a monitor  before it executes. For a class (static) method, the monitor associated with the Class object for the method's class is used. For an instance method, the monitor associated with this (the object for which the method was invoked) is used.

No comments: