Java and the Intrinsic Lock
I was working on converting a Java application to a multi-threaded application today and wanted to use the simplest means possible. This involves the following steps:
so this:
And when trying to synchronize multiple threads, both are wrong!!
The problem is that each object has an intrinsic lock, not each class. This is easiest to see in the second case. Because each thread is a different object, or the different thread objects contain their own instance of our Runnable class, every single lock is different. The first case has the same problem, not because the method is different in each case, but because the method is logically different.
So, what should we do?
In each case, we need to make the intrinsic lock static (or global to all instances of the class). In the first case, this can be accomplished by making the method static:
- Make the class implement Runnable or descend from the Thread class
- Put the previously sequential code into threads
- Use the "synchronized" keyword on methods that should be critical sections
- Join the threads before working on the results
so this:
private synchronized foo(){ // critical section stuff }is the same as this:
private foo(){ synchronized(this){ // critical section stuff } }
And when trying to synchronize multiple threads, both are wrong!!
The problem is that each object has an intrinsic lock, not each class. This is easiest to see in the second case. Because each thread is a different object, or the different thread objects contain their own instance of our Runnable class, every single lock is different. The first case has the same problem, not because the method is different in each case, but because the method is logically different.
So, what should we do?
In each case, we need to make the intrinsic lock static (or global to all instances of the class). In the first case, this can be accomplished by making the method static:
static synchronized foo(){ // critical section stuff }in the second case, we need some other object that is static to use as a lock.
static object myLock = new Object(); private foo(){ synchronize(myLock){ // critical section stuff } }Why would we use the second method? Probably because we want more fine grained protection over the locking than at the procedure level, or because we are referencing properties that should not be made static inside the function.
Comments