1

I am not clear the concept of

Java Thread acquires an object level lock when it enters into an instance synchronized java method and acquires a class level lock when it enters into static synchronized java method.

What does it mean When it says object level lock and class level lock ?

For example:

 public class Counter{
      private static int count = 0;
      private int count2 = 0;

      public static synchronized int getCount(){
           return count;
      }
      public synchronized setCount(int count2){
           this.count2 = count2;
      }
 } 

getCount() here will lock Counter.class object while setCount() will lock on current object(this). What does that this refer to ? Does that mean when getCount() get called another thread can't access setCount() since the whole class is locked ?

peter
  • 8,333
  • 17
  • 71
  • 94
  • This is well documented. What reading did you do? Here's a good start: http://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html – Gray Aug 21 '12 at 22:37
  • Related to http://stackoverflow.com/questions/5654654/static-synchronized-and-non-static-synchronized-methods-in-threads – Gray Aug 21 '12 at 22:38
  • possible duplicate of [How do synchronized static methods work in Java?](http://stackoverflow.com/questions/578904/how-do-synchronized-static-methods-work-in-java) – Gray Aug 21 '12 at 22:39
  • Better duplicate: http://stackoverflow.com/questions/1536064/what-is-the-difference-between-synchronized-and-static-synchronized – Gray Aug 21 '12 at 22:40
  • just another way of asking the question – peter Aug 21 '12 at 22:52
  • 2
    That's why it is a duplicate. – Gray Aug 21 '12 at 22:55
  • By the way, `this.count` is misleading code on a non-static method -- it make it look like `count` is an instance (ie, non-static) field. The only way someone would read that correctly is if they thought to mistrust the code and double check that `count` is an instance method. Qualifying static fields/methods via a reference is a bad habit to get into, because it conveys the wrong meaning. For instance, this will *not* throw a NPE: `Counter counter = null; counter.count` – yshavit Aug 21 '12 at 23:57

4 Answers4

1

In Java, each class and each instance of a class are endowed with their intrinsic locks. These are the locks acquired and release on entry to and exit from synchronized methods.

As usual this refers to the instance on which setCount() was called and because each instance has its own intrinsic lock the second call to setCount() will not block as long as it is invoked on another instance of your class, but an attempt to call setCount() on an instance on which another setCount() call is in progress will block.

Class lock and instance locks are different and thus getCount() and setCount() never get in each others way.

Adam Zalcman
  • 26,643
  • 4
  • 71
  • 92
  • I am not that clear about class lock, so in which case will a class lock block another thread ? – peter Aug 21 '12 at 22:43
  • A thread will block on entering `getCount()` if another thread's call to `getCount()` is in progress (i.e. another thread has acquired but not yet released the class level intrinsic lock). – Adam Zalcman Aug 21 '12 at 22:44
  • Yes. In fact, since `getCount()` is a static method, you're not really calling it on an instance (even if it looks so syntactically), but on the class. – Adam Zalcman Aug 21 '12 at 22:46
  • I think im kind of get it, so 2 threads call Counter.getCount(), and one of the thread will be blocked and have to wait, correct ? – peter Aug 21 '12 at 22:49
  • Yes. The second one will wait until the first leaves the method. – Adam Zalcman Aug 21 '12 at 22:50
1

static members are associated to the class not to a particular instance. As a result a synchronization on a static member effectively synchronizes over the whole class as static is a class member

instance members are associated with instances of the class (e.g. the intrisic this lock) so if you synchronize on a member field (non-static) or on this then you have a lock associated with an instance object.

In your example getCount synchronizes on the intrinsik lock of the class. Effectively you are doing:

public setCount(int count){
    synchronized(this){
        this.count = count;
    }  
}

You would be synchronizing in a class level if you did:

static Object count = new Object();  
synchronized(count){  

}
Cratylus
  • 52,998
  • 69
  • 209
  • 339
1

Each object in Java has a mutex. Since a class is represented by an object of type java.lang.Class, each class has a mutex too. synchronized instance methods lock the instance's mutex, while synchronized static methods lock the mutex for the corresponding java.lang.Class instance.

class C {
  synchronized T myMethod() { ... }

  static synchronized T myStaticMethod() { ... }
}

is equivalent to

class C {
  T myMethod() {
    synchronized (this) { ... }  // An object level lock.
  }

  static T myStaticMethod() {
    synchronized (C.class) { ... }  // A class level lock
    // is really just an object level lock an a Class.
  }
}

Once you know what object you're synchronizing on, you can understand the synchronized keyword by breaking it down.

synchronized (x) {
  body();
}

performs like

monitorenter(x);  // locks x or throws NullPointerException if x is null.
try {
  body();
} finally {
  monitorexit(x);  // unlocks x
}

where monitorenter and monitorexit are Java bytecode instructions that respectively block until they acquire the mutex, and release the mutex.

Since synchronized introduces a "protected region", like try ... finally, the lock will be released even if an exception is thrown, though killing the thread will leave the lock unreleased possibly leading to deadlock.

Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
1

What does it mean When it says object level lock and class level lock ?

When you lock on a static method you are locking on the Class object itself and there is one of these per ClassLoader. In your example,

public static synchronized int getCount(){

This is locking on the Counter.class object and is the same as:

public static int getCount() {
    synchronized (Counter.class) {
    }

If you are instead locking on a method that is not static then you are locking on the instance of the object that owns that method. In your example:

public synchronized void setCount(int count){

This is the same as locking on the particular Counter instance and is equivalent to:

public void setCount(int count){
    synchronized (this) {
       ...

So if you have 2 Counter objects, counter1 and counter2, and 1 thread is calling counter1.getCount() and the other is calling counter2.getCount() at the same time, then they will both lock on the same Class object and one will block the other.

But if the 2 threads are instead calling counter1.setCount(...) and counter2.setCount() they will be locking on different objects -- counter1 and counter2 respectively. They will not block each other.

As mentioned, it is very bad form to have asymmetry on your setters and getters and it is unusual to have either be static.

Does that mean when getCount() get called another thread can't access setCount() since the whole class is locked ?

No. If getCount() is called, the Counter.class is locked and when setCount(...) is called counter1 or counter2 is locked. The only time a lock blocks a thread is when the same object has been locked by another thread. Just because there is a lock on Counter.class does not mean that there is some sort of uber-class lock. The only time that will block another thread is if it too locks on Counter.class.

I'd take a moment to read Sun's great documentation on how synchronized works.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • So what does it mean by locking Counter.class. What does it block ? – peter Sep 02 '12 at 20:34
  • Locking on any object (the .class or an instance) does not block anything. The only time there is a block is when some other thread locks the _same_ object. So if `Counter.class` is locked, another thread will block if it goes to also lock `Counter.class` at the same time. Have you read the link I posted @user1389813? – Gray Sep 03 '12 at 15:29
  • yes i read all the links that you posted (those duplicates and the sun java tutorial), and I just want to confirm about this last thing: when you put a lock on Counter.class, it will only block threads that are trying to accessing another 'static' method not 'non-static' method, and object level lock will be the other way around, correct ? – peter Sep 03 '12 at 21:31
  • Yes. When you put a lock on `Counter.class` (by calling a `synchronized static` method) it will only block threads that also call a `synchronized static` method at the same time. Calling `synchronized` instance methods block other threads that also call a `synchronized` instance method at the same time. – Gray Sep 04 '12 at 13:15