Java Memory Model Revisited With Multiple Threads
This post explains how multiple threads comminuate with each other under Java memory model with details of memory operations using volatile given
Java Memory Model for Threads
So the following figure describes the general Java memory model: Every thread has its own working memory (thread local cache), and the working memory stores a separate copy of the variables in main memory. All of the operations within the thread like reading a variable, assigning a different value to a variable can only happen within the working memory, that is, it only affects the status of the copy of those variables in the working memory, the thread can not direct access or change the variable in the main memory skipping through the copies in its working memory: It is always first change or access the working memory, and then synchronize the content with main memory. Volatile is speical but Volatile varible (see Java Volatile Keyword Quick Tutorial for volatile details) also has a separate copy in the working memory, it is just the mechnism of volatile varaible requires it synchronize the content with memory immediately upon reading or writing (and there is some weak synchronization between reads/writes with the same variable), so it appears that thread is reading/writing a volatile variable directly from/to main memory, but do not be mistakened.
The Java memory model requires: different threads can not access the variables in other threads’ working memory, the communication bewtween threads has to be achived through the main memory by synchronization with the content between working memory and main memory.
As a result, if in the above figure, Thread 1 and Thread 2 want to communicate with each other like exchaging data (e.g., Thread 1 write new contents and want Thread 2 to see the new contents), it will go throught two steps:
- Thread 1 synchronize the data of those (shared) updated variables into main memory
- Thread 2 will need to read the latest content of those (shared) varaibles from the main memory and copy the updated contents into Thread 2’s working memory (this is another fact that thread can not directly access main memory, it always has to be through working memory, so does volatile variable)
Volatile Memory Operation Internal Details
Now we know the basics of how Java memory model works with multiple threads, lets revisit the example in Java Volatile Keyword Quick Tutorial to understand the interal memory details of reading and writing a volatile variable:
1 2 3 4 5 6 7 8 9 10 11 12 13 // obj is a shared mutable object // except for the volatileVariable, // other fields of obj are not volatile variables // Thread A write: obj.f2 = 2; obj.volatileVariable = obj.volatileVariable + 1; // write obj.f1 = 1; // Thread B read: int v1 = obj.f1; int value = obj.volatileVariable; // read int v2 = obj.f2;
Assume obj.f1 == -1 and obj.f2 == -2 and obj.volatileVariable == 1000 before the Thread A and Thread B execute the above statements.
We now can understand what would happend from Java memory model’s pespective: When Thread A writes 2 into obj.f2, it only writes the value into the working memory, in main memory and Thread B’s working memory, the value of obj.f2 is -2. Now Thread A writes new value into the volatile variable, firstly, the new value 1001 will be written into Thread A’s working memory, and because of the volatile keyword’s special requirement, the working memory of Thread A will be synchronized into the main memory (not sure it is the whole working memory or just the chunk of memory of the object obj), but anyways, now the main memory has obj.f2 == 2 and obj.volatileVariable == 1001, obj.f1 == -1, note the new value 1 is not written yet, the volatile keywork will keep the order of excution and JVM will gurantee those statements after volatile keyword will be excuted after. Now Thread A writes obj.f1 = 1, and in its working memory, it sees obj.f2 == 2, obj.volatileVarible == 1001, obj.f1 == 1, in main memory, it sees obj.f2 == 2, obj.volatileVarible == 1001, obj.f1 == -1 (we are not sure when JVM will synchroize obj.f1, I wll expalin more details later)
Now suppose Thread B starts reading. When it sees obj.f1, it will only read from the working memory, so as long as Thread B does not do synchronization, it will not see the latest value in main memory, regarding with obj.f1, no matter whether the value in main memory is updated or not, as long as Thread B does not synchronize with main memory, it always sees the old value of -1 for the moment. Similarly, even we try to read obj.f2, although we are sure that the obj.f2 in main memory is the updated value 2, at this moment before reading the volatile variable, Thread B still only sees the old value of obj.f2 == -2 in its working memory. Alright, now Thread B reads the volatile variable, it first synchorize with main memory by reading the content of obj in main memory and upate its working memory, now it reads obj.volatileVariable from working memory, it sees 1001, at the same time, obj.f2 is updated in the working memory because of the volatile, Thread B sees obj.f2 == 2 as well.
This is a realy good example to explain the Java Memory Model, hopefully it helps the make things more clear.
Here I explained how multiple threads comminuate with each other under Java memory and details of memory operations using volatile is given too.