Thursday, September 23, 2010

Synchronization - Issue with using non final objects for locks, specially primitive wrappers like Long, Boolean etc

Although best practices for synchronization suggest to use a final object only for acquiring lock on, most of the time we don't care about it much. This issue is more serious if try to acquire a lock on object of wrapper classes like Integer, Long, Boolean etc. Recently I cam across an interesting situation where it costed me my half day for ignoring best practices

Consider following code. Do you see the problem? Try executing it

public class MyClass {


private Boolean myObj = true;

public static void main(String[] args) {

MyClass a = new MyClass();

a.callMe();

}

public MyClass() {

}


public void callMe() {

synchronized (myObj) {

myObj = false;

myObj.notifyAll();

}

}

}


You will see

Exception in thread "main" java.lang.IllegalMonitorStateException

at java.lang.Object.notifyAll(Native Method)

at MyClass.callMe(MyClass.java:18)

at MyClass.main(MyClass.java:8)


Now try replacing callMe() code with following


public void callMe() {

synchronized (myObj) {

myObj.notifyAll();

myObj = false;

}

}


Wondering about why its working fine now!

that's because when you do following

myObj = false;


Now myObj is pointing to different immutable object of type Boolean with value false. Its not the object on which you synchronized and hence when you call notify on the new object referenced by myObj, it throws exception saying you don't own monitor for this object. You owned monitor of a object which was being reference before the assign statement

Suggestion: follow best practices. At least use only final objects for acquiring lock

1 comment: