Tuesday, October 11, 2011

Is Java concurrency for human beings ?

  Do you also have the bad feeling or uncertainty whenever you use volatile field modifier? The fact that compiler or processor can reorder statements or keep values in registers and that Java Memory Model and compiler is designed to allow aggressive optimizations is bad for our intuition about sufficiency of code synchronization.
  For instance, if you are iterating something on a boolean field ( while(! stop) ) until another thread changes it, the compiler doesn't know or see that and unless the boolean field is volatile, it might make an optimization on the assumption that the value of boolean is never going to change, so it eventually transforms it into an infinite loop. If it is a volatile field the compiler knows that it is not allowed to do such an operation.

What is important to be aware of !!!

  Knowing that processes use separate address spaces and all threads share one is irrelevant here. In Java Memory Model, memory that can be shared between threads is called shared memory or heap memory. All instance fields, static fields and array elements are stored in heap memory. Local variables are never shared between threads and are unaffected by the memory model.
  The most important thing is visibility of JVM inter-thread actions. Inter-thread action is an action performed by one thread that can be detected or influenced by another one (read & write volatile/non-volatile; locking & unlocking a monitor, actions when thread starts/terminates and some external actions).

  Visibility and so called happens before relationship differ for synchronization / locking and using volatile field modifier.

Blocking synchronization using Locks or synchronized methods / statements :
  1. thread A acquires a lock on an object and do some writes
  2. the Lock release pushes out the updates that thread 1 made to shared memory 
  3. thread B performs subsequent Lock acquire that grabs the updates that were performed by thread A by updating the cached values of fields from shared memory. 
  4. thread B performs read or write on updated values
   A synchronized method by default synchronizes on the instance it is being called on or the class object in case of a static method. The key synchronization concept for JVM concurrency is the monitor. Every object in a JVM has a monitor associated with it.
When you are using non blocking synchronization - using volatile field modifier, you practically perform so called happens-before relationship manually. 
  1. threads A, B, C change some field(s) (write) in the flow of their execution and perform a write to a volatile field
  2. each other thread that performs a read on that volatile field will see values of those changed fields updated in shared memory up until any of threads A, B, C wrote to it  
  Two accesses (reads of or writes to) the same variable are conflicting if at least one of them is a write. That is to say, if there are two accesses to a memory location and at least one of those is a write and the memory location isn't volatile, then the accesses must be ordered by happens-before relationship by some other means.    One of the means is using quite nifty java.util.concurrent.atomic package which provides a set of useful APIs that helps to make your software thread safe.    All memory accesses in Java are atomic by default, with the exception of long and double. All other data types are 32 bit. So we don’t have any issue as it will be single write. But for long & double it would be two writes. This can result in a situation where a thread sees the first 32 bits of a 64 bit value from one write and the second 32 bits from another write. Writes and reads of volatile long and double values are always atomic. So, if a thread A begins to set the field and a thread B attempts to get its value, then there is no guarantee it finishes before the read occurs. No atomicity guaranteed.

JSR-133 is the overall thread and Java Memory Model specification. JSR-166 relates to the utilities in java.util.concurrent package.

  I think that Java concurrency is for human beings. And after all I like it. There is other stuff that is quite inedible in comparison with Java concurrency, like practically useless java.lang.reflect.Type that looks it might come handy but finally you have to code all by yourself to get what you need from it :-)

No comments: