"I want to tell you about the volatile modifier. Do you know what that is?"
"Something to do with threads. I don't remember exactly."
"Then listen up. Here are some technical details for you:"
"A computer has two types of memory: global (ordinary) memory and memory built into the processor. The built-in processor memory is divided into registers, a first-level cache (L1), second-level cache (L2), and third-level (L3)."
"These types of memory have different speeds. The fastest and smallest memory is the registers, then the processor cache (L1, L2, L3), and finally the global memory (the slowest)."
"Global memory and the processor cache operate at wildly different speeds, so the Java machine allows each thread to store the most frequently used variables in local thread memory (in the processor cache)."
"Can this process somehow be controlled?"
"Not really. All the work is done by the Java machine. It's very intelligent when it comes to optimizing performance."
"But here's why I'm telling you this. There's one small problem. When two threads are working with the same variable, each one can store a copy in its own local cache. And then one thread might change the variable, but the second might not see the change, because it's still working with its own copy of the variable."
"Well, what can be done then?"
"Java's creators provided a special keyword for this situation: volatile. If a variable is accessed from different threads, you need to mark it with the volatile modifier, so the Java machine doesn't put it into the cache. This is how it usually looks:"
public volatile int count = 0;
"Oh, I remember. You already mentioned this. I already know this."
"Sure you do. But you remembered it only when I told you."
"Er, well, I've forgotten a little."
"Repetition is the mother of learning!"
"Here are a few new facts about the volatile modifier. The volatile modifier only guarantees that the variable will be read and written safely. It does not guarantee that it will be changed safely."
"What's the difference?"
"Look at how a the variable is changed:"
|Code||What really happens:||Description|
The variable count's value is copied from global memory to a processor register.
"Wow! So, all variables are changed only in the processor?"
"And the values are copied back and forth: from memory to the processor and back?"
"The volatile modifier guarantees that when the variable count is accessed it will be read from memory (step 1). And if a thread wants to assign a new value, it will definitely be in global memory (step 3)."
"But the Java machine doesn't guarantee that there won't be any thread switching between steps 1 and 3."
"So, incrementing the variable by 1 is actually three operations?"
"And if two threads simultaneously want to execute count++, then they could interfere with each other?"
"Yes, check it out:"
|Thread 1||Thread 2||Result|
"So, you can access the variable, but changing it is still risky?"
"Well, you can change it, just be careful ☺"
"synchronized is our best friend."