Comparison between volatile and synchronized in Java multi-thread

Source: Internet
Author: User
Tags visibility volatile

One, the visibility of the volatile keyword

To understand the volatile keyword, first understand the Java memory model, the Java memory model is abstracted as follows:

Can be seen:

① each thread has its own local memory space-the line stacks space??? When a thread executes, it reads the variable from main memory to the thread's own local memory space before manipulating the variable.

② the variable back to the main memory at some time after it has been manipulated

For a more detailed reference to the Java memory Model: in-depth understanding of the Java memory Model (i)--basic

Therefore, there is a memory visibility problem, see an example program: (from the book)

1PublicClass RunthreadExtendsThread {23PrivateBoolean isrunning =True;45PublicBooleanIsRunning () {6Returnisrunning;7}89Publicvoid Setrunning (Booleanisrunning) {10This.isrunning =isrunning;11}1213@Override14PublicvoidRun () {System.out.println ("Go into the Run method");16while (isrunning = =True) {17}SYSTEM.OUT.PRINTLN ("Thread execution completed");19}20}21st22PublicClassRun {23PublicStaticvoidMain (string[] args) {24try {25 runthread thread = Span style= "COLOR: #0000ff" >new Runthread ();   Thread.Start ()  Thread.Sleep (1000 Thread.setrunning (false 
                                                                             
                                                                              catch
                                                                               (interruptedexception e) {30  E.printstacktrace ();  }32 }33}         
                                                                                  

Run.java Line 28th, the main thread sets the shared variable in the thread runthread that is started to false, so that the while loop in the 14th row of the Runthread.java ends.

If, when we use the Jvm-server parameter to execute the program, the Runthread thread does not terminate! So there's a dead loop!!

Cause Analysis:

There are now two threads, one is the main thread and the other is runthread. They all try to modify the isrunning variable of the third row. Following the JVM memory model, the main thread reads the isrunning into the local thread memory space, modifies it, and then flushes it back to main memory.

When the JVM is set to run in-server mode, the thread will always read the isrunning variable in the private stack. Therefore, the runthread thread cannot read the isrunning variable that the main thread changed

Thus there is a dead loop, which causes the runthread to stop. in the case of effective JAVA, it is called "Activity failure" .

Workaround, decorate with the volatile keyword in the third line of code. Here, it forces the thread to take a volatile modified variable from the main memory.

    True

To expand, make sure that the condition is visible between threads when it is necessary to determine which thread can execute according to a certain condition. Therefore, it can be modified with volatile.

In summary, the volatile keyword has the effect of making a variable visible across multiple threads (visibility)

Second, the non-atomicity of the volatile keyword

The so-called atomicity is that a series of operating procedures are either all executed or not executed.

For example, the self-increment operation of a variable is i++ in three steps:

① read out the value of the variable i from memory

② Add the value of I to 1

③ the value after 1 is written back to memory

This means that i++ is not an atomic operation. Because it is divided into three steps, it is possible that when a thread executes to the ②, it is interrupted, which means that only two of them are executed, not all of them.

For a non-atomic nature of volatile, see an example:

1PublicClass MyThreadExtendsThread {2PublicVolatileStaticIntCount34PrivateStaticvoidAddcount () {5for (int i = 0; I < 100; i++) {6 count++;7}8 System.out.println ("count=" +count);9}1011@Override12PublicvoidRun () {13Addcount ();14}15}1617PublicClassRun {18PublicStaticvoidMain (string[] args) {mythread[] Mythreadarray =New mythread[100]; 20 for (int i = 0; i < ++) {21 mythreadarray[i] =  New MyThread ()  }23 24 for (int i = 0; i <" I++25  Mythreadarray[i].start ();  }27 }28}              

Line 2nd of the Mythread class, the count variable is modified with a volatile

Run.java the 20th row creates 100 threads in the For loop, the 25th line starts the 100 threads to execute Addcount (), each thread executes 100 times plus 1

The expected correct result should be 100*100=10000, but actually count does not reach 10000

The reason for this is that a volatile modified variable does not guarantee that its operation (self-increment) is atomic. (for self-increment operations, you can use Java's Atomic class Autoicinteger class to guarantee atomic self-increment)

For example, assuming I is self-increasing to 5, thread A reads I from main memory, a value of 5, stores it in its own thread space, performs an add 1 operation, and a value of 6. At this point, the CPU switches to thread B execution and reads the value of the variable i from the master-slave memory. Since thread A has not had time to write the result of adding 1 back to main memory, thread B has read I from main memory, so the variable i value read by thread B is still 5.

It is equivalent to thread B reading data that is obsolete, which results in thread insecurity. This situation is called "Security failure" in effective JAVA .

In conclusion, the security of threads is not guaranteed by volatile. (Atomic nature)

In addition,volatile keyword-modified variables are not optimized for instruction reordering. Here is an example of "in-depth understanding of Java Virtual Machine" to illustrate your understanding:

Thread A performs the following actions:

Map configoptions; char[] Configtext; volatile Boolean initialized = false;//thread A first reads the configuration information from the file, calls the process ... Processing configuration information, processing completed setting initialized to Trueconfigoptions = new HashMap (); configtext = Readconfigfile (fileName);p Rocessconfig ( Configtext, configoptions);//responsible for successfully initializing the configuration information configoptions initialized = true;

After thread B waits for thread A to initialize the configuration information successfully, use the configuration information to go to work ..... Thread B performs the following actions:

while (!initialized) {    sleep ();} Working with configuration information dosomethingwithconfig ();

If the initialized variable is not volatile decorated, it is possible to reorder the instructions in the code executed by thread A.

That is: The last line in the code executed by thread A:initialized = True reordering to the previous execution of the Processconfig method call, which means: The configuration information has not been initialized successfully. But the initialized variable has been set to true. Then it causes the while loop of thread B to "advance" and take a configuration message that has not been initialized successfully (Dosomethingwithconfig method) ....

Therefore, theinitialized variable must be modified with a volatile modifier. In this way, no command reordering occurs, that is, the initialized variable is initialized to true only after the configuration information has been successfully initialized by thread a. In summary , volatile modified variables prohibit command reordering (ordered)

Third, the comparison of volatile and synchronized

Volatile is used primarily when multiple thread-aware instance variables are changed, allowing each thread to get the most recent value. It enforces the visibility of the data by forcing threads to refer to variables from main memory each time, rather than reading variables from the thread's private memory.

For synchronized, refer to: Java multi-thread synchronized keyword--the feature of object lock

Comparison:

①volatile is lightweight and can only modify variables. Synchronized heavy-weight, also can be modified method

②volatile can only guarantee the visibility of the data and cannot be used for synchronization because multiple threads concurrently accessing volatile modified variables are not blocked.

Synchronized not only guarantees visibility, but also guarantees atomicity, because only the thread that obtains the lock can enter the critical section, guaranteeing that all statements in the critical section are executed. Blocking occurs when multiple threads scramble for synchronized lock objects.

Four, thread safety

Thread safety includes two aspects, ① visibility. ② Atomic nature.

From the example above, it can be seen that using volatile alone does not guarantee thread safety. and synchronized can implement thread security.

Comparison between volatile and synchronized in Java multi-thread

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.