[.net multithreading] volatile excerpt

  • 一、volatile introduce

volatile The keyword indicates that a field can be modified by multiple concurrently executing threads. Fields declared as  volatile are not subject to compiler optimizations (assumed to be accessed by a single thread). This ensures that the field is presented with the latest value at all times.

volatile The modifier is typically used for   fields that are accessed by multiple threads but the access is not serialized using a lock statement.

volatile Keywords can be applied to the following types of fields:

  • reference type.

  • Pointer type (in an unsafe context). Note that while the pointer itself can be mutable, the object it points to cannot. In other words, you cannot declare "pointer to mutable object".

  • Types such as sbyte, byte, short, ushort, int, uint, char, float, and bool.

  • An enumeration type with one of the following base types: byte, sbyte, short, ushort, int, or uint.

  • A generic type parameter known to be a reference type.

  • IntPtr 和 UIntPtr

The mutable keyword can only be applied to class or struct fields. Local variables cannot be declared as  volatile.

  • 2. In-depth analysis

  It is easiest to explain the difference between volatile and synchronized. Volatile is a variable modifier, while synchronized acts on a piece of code or method; see the following three get codes:

  1. int i1;              int geti1() {return i1;}
  2. volatile int i2;  int geti2() {return i2;}
  3. int i3;              synchronized int geti3() {return i3;}

  geti1() gets the value of i1 stored in the current thread. Multiple threads have multiple copies of the i1 variable, and these i1s can be different from each other. In other words, another thread may have changed the value of i1 in its thread, and this value may not be the same as the value of i1 in the current thread. In fact, Java has an idea called the "main" memory area, where the current "exact value" of a variable is stored. Each thread can have its own copy of the variable, and the value of this variable copy can be different from the one stored in the "main" memory area. So there is actually a possibility: the value of i1 in the "main" memory area is 1, the value of i1 in thread 1 is 2, the value of i1 in thread 2 is 3 - this changes them in both thread 1 and thread 2 The respective i1 value, and this change has not yet been passed to the "main" memory area or other threads.
   And geti2() gets the i2 value of the "main" memory area. Variables decorated with volatile are not allowed to have copies of variables that differ from the "main" memory area. In other words, a variable that is volatile must be synchronized in all threads; any thread that changes its value, all other threads immediately get the same value. Of course, volatile-modified variable accesses consume a little more resources than normal variables, because it is more efficient for a thread to have its own copy of the variable.
  Now that the volatile keyword has achieved data synchronization between threads, what should be synchronized for? Hehe, there are two differences between them. First, synchronized acquires and releases monitors—a well-known fact that monitors enforce a block of code to be executed by only one thread at a time if two threads use the same object lock. However, synchronized also synchronizes memory: in fact, synchronized synchronizes the entire thread's memory in the "main" memory area. Therefore, the execution of the geti3() method does the following steps:
1. The thread requests to acquire the lock of the object monitoring this object (assuming it is not locked, otherwise the thread waits until the lock is released)
2. The data in the thread memory is eliminated, from the "main" Read in the memory area (the Java virtual machine can optimize this step... [I don't know how to express it later, sweat])
3. The block of code is executed
4. Any changes to the variable can now be safely written to the "main" memory area (although the geti3() method does not change the variable value)
5. The thread releases the object lock monitoring the this object
  so volatile just Synchronizes the value of a variable between thread memory and "main" memory, while synchronized synchronizes the value of all variables by locking and unlocking a monitor. Obviously synchronized consumes more resources than volatile.

 More simple explanation:

Volatile literally means volatile, unstable. In C#, it can be understood almost the same way.

When the compiler optimizes the code, it may store the frequently used code in the Cache, and then directly read the Cache instead of the memory in the next call, which greatly improves the efficiency. But problems also followed.

In a multithreaded program, if another thread changes the value of a variable after a variable is put into the Cache, the thread cannot know the change. It may directly read the data in the Cache. But unfortunately, the data in the Cache has expired, and the dirty data is read out of time. Then a bug will appear.

Declaring the variable with Volatile solves this problem. A variable declared with Volatile is equivalent to telling the compiler, I don't want to write this variable to Cache, because this variable may change.

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325347221&siteId=291194637