Learn Java multi-thread volatile domain _java

Source: Internet
Author: User
Tags static class visibility volatile

Objective

Sometimes it is too expensive to use synchronization just to read or write one or two instance domains, and the volatile keyword provides a lock-free mechanism for synchronous access to instance domains. If you declare a domain to be volatile, the compiler and the virtual machine will know that the domain is likely to be updated concurrently by another thread. Before we get to the volatile keyword, we need to understand the concepts of the memory model and three features in concurrent programming: atomicity, Visibility, and ordering.

1. Java memory model and atomicity, visibility and ordering

The Java memory model stipulates that all variables exist in main memory, and each thread has its own working memory. All operations of a thread on a variable must be performed in working memory, not directly on main memory. And each thread cannot access the working memory of another thread.
In Java, execute the following statement:

int i=3;

The execution thread must first assign to the cache row of the variable I in its own worker thread before writing to the master. Instead of writing the value 3 directly into main memory.
What guarantees does the Java language itself provide for atomicity, visibility, and ordering?

of atomic

Read and assign operations to variables of the base data type are atomic operations, that is, these operations are not interruptible, executed, or not executed.
Take a look at the following code:

x = ten;    Statement 1
y = x;     Statement 2
x + +;      Statement 3
x = x + 1;   Statement 4

Only Statement 1 is an atomic operation, and the other three statements are not atomic in nature.
Statement 2 actually contains 2 operations, it first reads the value of x, and then writes X's value to the working memory, although the value of x and the value of x to the working memory 2 operations are atomic operations, but the combination is not atomic operation.
Similarly, X + + and × = x+1 include 3 operations: Reading the value of x, adding 1 operations, and writing a new value.
That is, only a simple read, assignment (and must assign a number to a variable, and the reciprocal assignment between variables is not atomic) is the atomic operation.
Many classes in the Java.util.concurrent.atomic package use highly efficient machine-level instructions (rather than locks) to ensure the atomicity of other operations. For example, the Atomicinteger class provides methods Incrementandget and Decrementandget, which respectively increase and decrement an integer by atomic means. You can safely use the Atomicinteger class as a shared counter without synchronization.
The package also contains Atomicboolean,atomiclong and atomicreference these atomic classes are used only by system programmers who develop concurrent tools, which should not be used by application programmers.

Visibility of

Visibility refers to the visibility between threads, and the state of a thread modification is visible to another thread. Which is the result of a thread modification. Another thread can see it right away.
When a shared variable is volatile decorated, it guarantees that the modified value is immediately updated to main memory, so that it is visible to other threads and reads the new value in memory when another thread needs to read it.
Ordinary shared variables do not guarantee visibility, because when the normal shared variable is modified and when it is written to main memory is indeterminate, when other threads go to read, the memory may still be the original old value, so the visibility can not be guaranteed.

Order of

In the Java memory model, the compiler and the processor are allowed to reorder the instructions, but the reordering process does not affect the execution of single-threaded threads, but it affects the correctness of concurrent execution of multithreading.
Volatile keyword can be used to ensure a certain "order". In addition, synchronized and lock can be used to ensure order, it is clear that synchronized and lock guarantee that each moment is a thread to execute synchronization code, which is the equivalent of the thread in order to execute the synchronization code, the natural guarantee of order.

2. Volatile keyword

Once a shared variable (a class's member variable, a class's static member variable) is volatile modified, it has two-layer semantics:

    • Guarantees the visibility of different threads when manipulating the variable, that is, a thread modifies the value of a variable, which is immediately visible to other threads.
    • instruction reordering is prohibited.

Read a piece of code first, if thread 1 executes first, thread 2 executes after:

Thread 1
Boolean stop = false;
while (!stop) {
  dosomething ();
}

Thread 2
stop = true;

Many people may use this notation when interrupting threads. But in fact, does this code run exactly right? Is it certain that the thread will be interrupted? Not necessarily, perhaps for most of the time, this code can break the thread, but it may also cause a disconnection (although this is a small possibility, it can cause a dead loop if this happens).
Why is it possible to cause a thread to be disconnected? Each thread has its own working memory during the run, so thread 1 will copy the value of the stop variable to its working memory when it is running. So when thread 2 changes the value of the stop variable, but before it can be written into main memory, and thread 2 turns to do something else, thread 1 does not know that the thread 2 changes to the stop variable, so it continues to loop.
But with volatile it becomes different:

    • Using the volatile keyword forces the modified value to be written to main memory immediately;
    • With the volatile keyword, when thread 2 is modified, the cached row of the cached variable stop in the working memory of thread 1 is invalidated;
    • Because the cached row of the cached variable stop in thread 1 's working memory is invalid, thread 1 reads the main memory again when the value of the variable stop is read again.

Does the volatile guarantee atomic sex?

We know that the volatile keyword guarantees the visibility of the operation, but does volatile guarantee that the operation of the variable is atomic?

 public class Test {public volatile int inc = 0;
  public void Increase () {inc++;
    public static void Main (string[] args) {final Test test = new test ();
            for (int i=0;i<10;i++) {new Thread () {public void run () {for (int j=0;j<1000;j++)
        Test.increase ();
      };
    }.start ();
    }//Ensure that all previous threads are executed while (Thread.activecount () >1) Thread.yield ();
  System.out.println (TEST.INC); }
}

This code is not consistent in each run, is a number less than 10000, as mentioned earlier, the self-operation is not atomic, it includes reading the original value of the variable, to add 1 operations, write working memory. So that means the three child operations of the self augmentation operation may be split open.
If the value of the variable inc is 10, thread 1 increases the variable by itself, thread 1 reads the original value of the variable inc first, then thread 1 is blocked, then thread 2 makes the variable self operation, and thread 2 reads the original value of the variable inc, because thread 1 only reads the variable Inc. Instead of modifying the variables, so it does not cause the cached variables in the working memory of thread 2 to be invalid, so thread 2 will go directly to main memory to read the INC value, discover the value of INC 10, then add 1 and then write 11 to the working memory and finally to main memory. Thread 1 then goes on to add 1, since the value of the INC has been read, noting that at this point in the working memory of thread 1, the value of Inc. is still 10, so thread 1 to the INC 1 operation after the value of INC is 11, and then 11 to the working memory, and finally to main memory Then two threads had a single self increase operation, Inc. only increased by 1.
Self-augmentation is not an atomic operation, and volatile does not guarantee that any manipulation of variables is atomic.

Can volatile guarantee order?

In the preceding mentioned volatile keyword can prohibit order reordering, so volatile can guarantee to some extent order.
The volatile keyword prohibits order reordering with two layers of meaning:

    • When a program executes a read or write operation to a volatile variable, the changes in the previous operation must have been made, and the result is visible to the subsequent operation;
    • When the instruction is optimized, the statements that are accessed by the volatile variable cannot be executed behind it, nor can the statements following the volatile variable be executed before it.

3. Correct use of volatile keywords

The Synchronized keyword is to prevent multiple threads from executing a piece of code at the same time, which can greatly affect program execution efficiency, while the volatile keyword performs better than synchronized in some cases. However, note that the volatile keyword cannot be substituted for the Synchronized keyword because the volatile keyword does not guarantee the atomic nature of the operation. Generally, the following 2 conditions must be used for volatile:

    • Write operations on variables do not depend on the current value
    • The variable is not included in the invariant with other variables

The first condition is that it cannot be an volatile operation, which has been mentioned above that does not guarantee atomicity.
The second condition, let's give an example. It contains a invariant: the lower bound is always less than or equal to the upper bound

public class Numberrange {
  private volatile int lower, upper;
  public int Getlower () {return lower;}
  public int Getupper () {return upper;}
  public void Setlower (int value) { 
    if (Value > Upper) 
      throw new IllegalArgumentException (...);
    lower = value;
  }
  public void Setupper (int value) { 
    if (value < lower) 
      throw new IllegalArgumentException (...);
    upper = value;
  }
}

This approach restricts the state variables of the scope, so defining the lower and upper fields as volatile types does not fully implement the thread safety of the class, and thus still needs to use synchronization. Otherwise, if it happens that two threads execute Setlower and setupper at the same time using inconsistent values, the scope is in an inconsistent state. For example, if the initial state is (0, 5, at the same time, thread A calls Setlower (4) and thread B calls Setupper (3), it is obvious that these two operations are not eligible for the cross deposit, then two threads will be used to protect the invariant type of check, so that the final range value is (4 , 3), this is obviously wrong.
In fact, to ensure the atomic nature of the operation can be used volatile, the use of volatile has two main scenarios:

Status flag

Volatile Boolean shutdownrequested;
...
public void shutdown ()
 { 
 shutdownrequested = true;
 }
public void DoWork () {while 
  (!shutdownrequested) { 
    //do Stuff
  }
}

It is possible to invoke the shutdown () method from outside the loop-that is, on another thread-so a synchronization is required to ensure that the visibility of the shutdownrequested variable is implemented correctly. However, writing loops using the synchronized block is much more cumbersome than writing with the volatile status flag. Because volatile simplifies encoding and the status flag does not depend on any other state within the program, it is a good place to use volatile.

Double check Mode (DCL)

public class Singleton { 
  Private volatile static Singleton instance = null; 
  public static Singleton getinstance () { 
    if (instance = null) { 
      synchronized (this) { 
        if (instance = null) {
   instance = new Singleton (); 
    }} return instance; 
  } 

Using volatile here will affect performance more or less, but it is worth sacrificing this performance, given the correctness of the program.
The DCL advantage is that the resource utilization is high, the first time executes getinstance the single Case object is instantiated, the efficiency is high. The disadvantage is that the first load of the reaction slightly slower, in the high concurrent environment also has a certain defect, although the probability of the occurrence is very small.
DCL Although to a certain extent to solve the consumption of resources and redundant synchronization, line Cheng and so on, but he still in some cases will be the problem of failure, that is, DCL failure, in the Java Concurrent programming practice is recommended to use the following code (static internal class single example mode) to replace the DCL:

public class Singleton { 
  private Singleton () {
  } public
   static Singleton getinstance () { 
    return singletonholder.sinstance; 
  } 
  private static class Singletonholder { 
    private static final Singleton sinstance = new Singleton (); 
  } 
 

About double check to view

4. Summary

Compared to locks, the Volatile variable is a very simple but also very fragile synchronization mechanism that in some cases provides better performance and scalability than locks. If you strictly follow the volatile usage condition that the variable is truly independent of other variables and its previous values, in some cases you can use volatile instead of synchronized to simplify the code. However, code that uses volatile is often more error-prone than code that uses locks. This article describes two of the most common use cases where you can use volatile instead of synchronized, and in other cases we'd better use synchronized.

The above is the entire content of this article, I hope to help you learn.

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.