Wednesday, December 31, 2008

Sharing variable between threads

I take no credit for what I am going to write here, It's the result of reading few good books on Java Concurrency.

Lots of programmers think that synchronization is to be used when multiple threads are modifying a shared variable. What about a situation when we know that only one particular thread will modify the shared variable and all others will only read that variable. Should we be using synchronization?
Consider following example and think about the output:
public class Test {
private static boolean ready;
private static int number;

private static class ReaderThread extends Thread {
public void run(){
while(!ready){
Thread.yield();
}
System.out.println(number);
}
}
public static void main(String[] args)throws Exception {
new ReaderThread().start();
number=42;
ready = true;
}
}

I had my answer 42, its got to be 42. But its not always true. Its quite possible that thread does not see the value of ready and get stuck in infinite loop.
When you run java process with '-server' option, according to JVM specs, JVM can do some optimization. This optimization involves, keeping the value of the local thread specific variables in local registers or caches and update the memory location at will. So unless JVM knows that a particular variable is shared between threads, it can apply some optimizations. If you run the process with '-client' option, JVM does not apply any optimizations and hence you will always see the result as you would expect. Even in production environment, things like above are hard to catch and sometime it can run correctly for its entire life.
In above example, there is no hint to JVM to know that 'ready' is shared, so it can opt to keep the changes in variable in local cache and hence other threads can see the stale value.
So whenever there is any sharing use either final or volatile or synchronization.
Volatile forces JVM to update the shared memory location with each update on the variable and hence all the threads will see the updates value. Similarly with use of synchronization, JVM knows that it has to update the memory location for each update in shared variable.