Synchronizing Static Methods

Throughout this chapter on synchronization, we kept referring to “obtaining the object lock.” But what about static methods? When a synchronized static method is called, which object are we referring to? A static method does not have a concept of the this reference. It is not possible to obtain the object lock of an object that does not exist. So how does synchronization of static methods work? To answer this question, we will introduce the concept of a class lock. Just as there is an object lock that can be obtained for each instance of a class (object), there is a lock that can be obtained for each class. We will refer to this as the class lock . In terms of implementation, there is no such thing as a class lock, but it is a useful concept to help us understand how this all works.

When a static synchronized method is called, the program obtains the class lock before calling the method. This mechanism is identical to the case in which the method is not static; it is just a different lock. The same rule applies: if a synchronized static method calls another synchronized static method of the same class, the system is smart enough to support the nesting of class locks.

But how is the class lock related to the object lock? Apart from the functional relationship between the two locks, they are not operationally related at all. These are two distinct locks. The class lock can be grabbed and released independently of the object lock. If a nonstatic synchronized method calls a static synchronized method, it acquires both locks. Achieving deadlock between these two locks is a little difficult (but not impossible) to accomplish since a static method cannot call a nonstatic method without an object reference.

If a synchronized static method has access to an object reference, can it call synchronized methods of that object or use the object to lock a synchronized block? Yes: in this case the program first acquires the class lock when it calls the synchronized static method and then acquires the object lock of the particular object:

public class MyStatic {
    public synchronized static void staticMethod(MyStatic obj) {
        // Class lock acquired
        obj.nonStaticMethod();

        synchronized (obj) {
        // Class and object locks acquired
        }    
    }
    public synchronized void nonStaticMethod() {
        // Object lock acquired
    }
}

Can a nonstatic method grab the static lock without calling a synchronized static method? In other words, can a synchronized block apply to the class lock? For example, something like this:

public class ClassExample {
    synchronized void process() {
        synchronized (the class lock) {
        // Code to access static variables of the class
        }
    }
}

The main reason for a nonstatic method to grab a class lock is to prevent a race condition for variables that apply to the class (i.e., static variables). This can be accomplished by calling a static synchronized method of the class. If for some reason this is not desired, we can also use the synchronized block mechanism on a common static object (using a static instance variable would probably be the best technique for storing such a common object). For example, we could use an object stored in a common location that can be accessed by all objects of a particular class type:

public class ClassExample {
    private static Object lockObject = new Object();
    synchronized void process() {
        synchronized (lockObject) {
            // Code to access static variables of the class
        }
    }
}

Finally, if creating a new object is not desired, you may also obtain the class object (that is, the instance of the java.lang.Class class) that represents the class itself. Objects of this class are used to represent classes in the system. For our purposes, we are using this class because there is a one-to-one ratio of classes and objects of the Class class that represents the classes. This class object can be obtained as follows:

public class ClassExample {
    synchronized void process() {
        synchronized (Class.forName("ClassExample")) {
            // Code to access static variables of the class
        }
    }
}

A call to the forName() method of the Class class returns this object. We can then use this class object as the locking object via the synchronized block mechanism.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset