Simplest and understandable example of volatile keyword in Java

后端 未结 12 810
梦谈多话
梦谈多话 2020-11-28 19:43

I\'m reading about volatile keyword in Java and completely understand the theory part of it.

But, what I\'m searching for is, a good case example, which sho

相关标签:
12条回答
  • 2020-11-28 20:43

    volatile is not going to necessarily create giant changes, depending on the JVM and compiler. However, for many (edge) cases, it can be the difference between optimization causing a variable's changes to fail to be noticed as opposed to them being correctly written.

    Basically, an optimizer may choose to put non-volatile variables on registers or on the stack. If another thread changes them in the heap or the classes' primitives, the other thread will keep looking for it on the stack, and it'll be stale.

    volatile ensures such optimizations don't happen and all reads and writes are directly to the heap or another place where all threads will see it.

    0 讨论(0)
  • 2020-11-28 20:43

    The volatile keyword tells the JVM that it may be modified by another thread. Each thread has its own stack, and so its own copy of variables it can access. When a thread is created, it copies the value of all accessible variables in its own memory.

    public class VolatileTest {
        private static final Logger LOGGER = MyLoggerFactory.getSimplestLogger();
    
        private static volatile int MY_INT = 0;
    
        public static void main(String[] args) {
            new ChangeListener().start();
            new ChangeMaker().start();
        }
    
        static class ChangeListener extends Thread {
            @Override
            public void run() {
                int local_value = MY_INT;
                while ( local_value < 5){
                    if( local_value!= MY_INT){
                        LOGGER.log(Level.INFO,"Got Change for MY_INT : {0}", MY_INT);
                         local_value= MY_INT;
                    }
                }
            }
        }
    
        static class ChangeMaker extends Thread{
            @Override
            public void run() {
    
                int local_value = MY_INT;
                while (MY_INT <5){
                    LOGGER.log(Level.INFO, "Incrementing MY_INT to {0}", local_value+1);
                    MY_INT = ++local_value;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) { e.printStackTrace(); }
                }
            }
        }
    }
    

    try out this example with and without volatile.

    0 讨论(0)
  • 2020-11-28 20:47

    When a variable is volatile, it is guaranteeing that it will not be cached and that different threads will see the updated value. However, not marking it volatile does not guarantee the opposite. volatile was one of those things that was broken in the JVM for a long time and still not always well understood.

    0 讨论(0)
  • 2020-11-28 20:48

    For your particular example: if not declared volatile the server JVM could hoist the keepRunning variable out of the loop because it is not modified in the loop (turning it into an infinite loop), but the client JVM would not. That is why you see different results.

    General explanation about volatile variables follows:

    When a field is declared volatile, the compiler and runtime are put on notice that this variable is shared and that operations on it should not be reordered with other memory operations. Volatile variables are not cached in registers or in caches where they are hidden from other processors, so a read of a volatile variable always returns the most recent write by any thread.

    The visibility effects of volatile variables extend beyond the value of the volatile variable itself. When thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of all variables that were visible to A prior to writing to the volatile variable become visible to B after reading the volatile variable.

    The most common use for volatile variables is as a completion, interruption, or status flag:

      volatile boolean flag;
      while (!flag)  {
         // do something untill flag is true
      }
    

    Volatile variables can be used for other kinds of state information, but more care is required when attempting this. For example, the semantics of volatile are not strong enough to make the increment operation (count++) atomic, unless you can guarantee that the variable is written only from a single thread.

    Locking can guarantee both visibility and atomicity; volatile variables can only guarantee visibility.

    You can use volatile variables only when all the following criteria are met:

    • Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever updates the value;
    • The variable does not participate in invariants with other state variables; and
    • Locking is not required for any other reason while the variable is being accessed.

    Debugging tip: be sure to always specify the -server JVM command line switch when invoking the JVM, even for development and testing. The server JVM performs more optimization than the client JVM, such as hoisting variables out of a loop that are not modified in the loop; code that might appear to work in the development environment (client JVM) can break in the deployment environment (server JVM).

    This is an excerpt from "Java Concurrency in Practice", the best book you can find on this subject.

    0 讨论(0)
  • 2020-11-28 20:48

    What is volatile keyword ?

    volatile keyword prevents caching of variables.

    Consider the code ,first without volatile keyword

    class MyThread extends Thread {
        private boolean running = true;   //non-volatile keyword
    
        public void run() {
            while (running) {
                System.out.println("hello");
            }
        }
    
        public void shutdown() {
            running = false;
        }
    }
    
    public class Main {
    
        public static void main(String[] args) {
            MyThread obj = new MyThread();
            obj.start();
    
            Scanner input = new Scanner(System.in);
            input.nextLine(); 
            obj.shutdown();   
        }    
    }
    

    Ideally,this program should print hello until RETURN key is pressed. But on some machines it may happen that variable running is cached and you cannot change its value from shutdown() method which results in infinite printing of hello text.

    Thus using volatile keyword ,it is guaranteed that your variable will not be cached ,ie will run fine on all machines.

    private volatile boolean running = true;  //volatile keyword
    

    Thus using volatile keyword is a good and safer programming practice.

    0 讨论(0)
  • 2020-11-28 20:50

    Objects that are declared as volatile are usually used to communicate state information among threads,To ensure CPU caches are updated, that is, kept in sync, in the presence of volatile fields, a CPU instruction, a memory barrier, often called a membar or fence, is emitted to update CPU caches with a change in a volatile field’s value.

    The volatile modifier tells the compiler that the variable modified by volatile can be changed unexpectedly by other parts of your program.

    The volatile variable must be used in Thread Context only. see the example here

    0 讨论(0)
提交回复
热议问题