Thursday, April 24, 2014

Synchronization in Java : class and object locking concept

People talk about two types of multi-threaded locking - object and class. In my knowledge, locking is done on objects only. Let me explain.

Case 1: On objects we create using new or factory methods etc.
void synchronized myMethod(Type param) {
  //will lock on the instance used to call this method
}
or
synchronized(this) {
 //will lock on current object
}
or
synchronized(obj1) {
 //will lock on specified obj1 object
}

Case 2: On java.lang.Class objects This is called class lock, and can be used with static fields or methods or blocks, as they belong to class and shared among all the objects, and other class properties.
static void synchronized method() {
  //will lock the Class object
}
or
static {
  synchronized(SomeClass.class){
    int a = 2;
  }
}
This is also object locking because classes are loaded into the Method Area in the JVM, and all the static members of the class are wrapped inside a java.lang.Class object created by JVM. So behind abstraction, its that class' object locking and in the front picture, we consider it class locking.
So I can also infer one more thing. Just as objects locked by a thread can not be acquired by another thread as long as it is not released by first thread, class locking (the java.lang.Class instance) also works in same manner as it is essentially object locking only.

Now slightly digging into the class locking concept. Taking the following class hierarchy.
class Animal {
 static synchronized void eat() {
  //generic eating habits
 }
}

class Dog extends Animal implements Runnable{
 public void run() {
  Dog.eat();
 }
}
The above code will result into locking Animal.class object only whether we call eat() method using Dog or Animal, because eat() is present in only Animal class.
Let's change the scenario.
class Animal {
 static synchronized void eat() {
  //generic eating habits
 }
}

class Dog extends Animal implements Runnable{
 public void run() {
  Dog.eat();
 }
 static synchronized void eat() {
  //doggy eating habits
 }
}
Now that eat() method is present in both classes, lock will be acquired only on that class on which the method was called. Dog.class in above case. If it was Animal.eat(), will lock Animal.class.
Lets do a little bit more.
class Animal {
 static synchronized void eat() {
  //generic eating habits
 }
}

class Dog extends Animal implements Runnable{
 public void run() {
  Dog.eat();
 }
 static synchronized void eat() {
  super.eat();
 }
}
When started, the Dog thread will go on to lock the Dog.class and then Animal.class.

Note:
  1. synchronized keyword helps in mutual exclusion, so when a lock is acquired on any object by a thread, only the synchronized properties are kept safe from manipulation by other threads, the non-synchronized properties like variables or methods etc, are free to get manipulated.
  2. Each object has a synchronization lock, which can be owned by only one thread at a time. However, a thread can own multiple locks at the same time.
  3. Synchronization can help to eliminate race conditions but can introduce deadlock into the application..

No comments:

Post a Comment

Liked or hated the post? Leave your words of wisdom! Thank you :)