How is class level locking achieved in java?

2019-05-30 23:32发布

问题:

I am aware of locking concepts with synchronization of static and non static methods to lock classes and instances respectively. What I am not able to understand is, how is class level lock achieved? I mean, class is a template only, with no physical significance. So, when we say that class level locking is achieved with synchronizing static methods what happens then? Do all the objects of that class get locked or some other process?

With what I could find out with my search is that there are class objects (Class.class) and lock is acquired on this class object. But then how are all instances of that class also locked?

回答1:

Do all the objects of that class get locked or some other process?

First, let's talk about what what it means to "lock" an object.

Foobar foobar = new Foobar();

synchronized (foobar) {
    ...
}

You might say that the foobar object is "locked" when a thread is in the synchronized block. But what does that do for the program? A lot of newbies make the mistake of thinking that it will prevent other threads from accessing the object. But, that is not true. What synchronized does--the only thing synchronized does--is to guarantee that no more than one thread can be synchronized on the same object at the same time.

The programmer's intent in the example above might be to prevent other threads from seeing foobar in an inconsistent state. In that case, every method and every fragment of code that accesses foobar must be synchronized on foobar. Imagine foobar as big room with many doors. Each method that uses foobar is like a different door. If you want to keep people out of the room, it doesn't help to lock just one door. You have to lock all of them.

So now, to your question:

when we say that class level locking is achieved with synchronizing static methods what happens then?

Simple. This:

class Foobar {
    static synchonized void do_something() {
        ...
    }
}

Does exactly the same as this:

class Foobar {
    static void do_something() {
        synchronized(Foobar.class) {
            ...
        }
    }
}

You always synchronize on an Object. Well, a class is an Object. When a static method is synchronized, that just means that the method body is synchronized on the class object.

Since a class is a singleton object, that means that no two threads can get into the same static synchronized method at the same time. In my earlier example, the variable foobar could refer to different objects at different times, but in the static example, Foobar.class is guaranteed always to refer to the same singleton.


Edit: As, @Danny pointed out, there is no connection between a block that is synchronized on the Foobar class, (my second example) and a block that is synchronized on an instance of the Foobar class (my first example). The instance and the class object are two different objects, so nothing prevents one thread from synchronizing on the instance while another thread is synchronized on the class. Likewise, nothing prevents two different threads from synchronizing on two different instances. Another mistake that newbies often make is to think that only one thread at a time can enter this synchronized block:

Integer n = ...;

synchronized (n) {
    n = n+1;
    ...
}

But it's not true. It's not the variable, n, that is locked, it's a particular instance of the Integer class. Each thread that enters the block creates a new Integer instance and assigns it to n. So when the next thread comes along, n no longer refers to the same instance that the first thread has synchronized.