Simplest and understandable example of volatile keyword in Java

后端 未结 12 808
梦谈多话
梦谈多话 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:23

    Variable Volatile: Volatile Keyword is applicable to variables. volatile keyword in Java guarantees that value of the volatile variable will always be read from main memory and not from Thread's local cache.

    Access_Modifier volatile DataType Variable_Name;
    

    Volatile Field: An indication to the VM that multiple threads may try to access/update the field's value at the same time. To a special kind of instance variables which has to shared among all the threads with Modified value. Similar to Static(Class) variable, Only one copy of volatile value is cached in main memory, So that before doing any ALU Operations each thread has to read the updated value from Main memory after ALU operation it has to write to main memory direclty. (A write to a volatile variable v synchronizes-with all subsequent reads of v by any thread) This means that changes to a volatile variable are always visible to other threads.

    Here to a nonvoltaile variable if Thread t1 changes the value in t1's cache, Thread t2 can't access the changed value untill t1 writes, t2 read from main memory for the most recent modified value, which may lead to Data-Inconsistancy.

    volatile cannot be cached - assembler

        +--------------+--------+-------------------------------------+
        |  Flag Name   |  Value | Interpretation                      |
        +--------------+--------+-------------------------------------+
        | ACC_VOLATILE | 0x0040 | Declared volatile; cannot be cached.|
        +--------------+--------+-------------------------------------+
        |ACC_TRANSIENT | 0x0080 | Declared transient; not written or  |
        |              |        | read by a persistent object manager.|
        +--------------+--------+-------------------------------------+
    

    Shared Variables: Memory that can be shared between threads is called shared memory or heap memory. All instance fields, static fields, and array elements are stored in heap memory.

    Synchronization: synchronized is applicable to methods, blocks. allows to execute only 1-thread at a time on object. If t1 takes control, then remaining threads has to wait untill it release the control.

    Example:

    public class VolatileTest implements Runnable {
    
        private static final int MegaBytes = 10241024;
    
        private static final Object counterLock = new Object();
        private static int counter = 0;
        private static volatile int counter1 = 0;
    
        private volatile int counter2 = 0;
        private int counter3 = 0;
    
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                concurrentMethodWrong();
            }
    
        }
    
        void addInstanceVolatile() {
            synchronized (counterLock) {
                counter2 = counter2 + 1;
                System.out.println( Thread.currentThread().getName() +"\t\t « InstanceVolatile :: "+ counter2);
            }
        }
    
        public void concurrentMethodWrong() {
            counter = counter + 1;
            System.out.println( Thread.currentThread().getName() +" « Static :: "+ counter);
            sleepThread( 1/4 );
    
            counter1 = counter1 + 1;
            System.out.println( Thread.currentThread().getName() +"\t « StaticVolatile :: "+ counter1);
            sleepThread( 1/4 );
    
            addInstanceVolatile();
            sleepThread( 1/4 );
    
            counter3 = counter3 + 1;
            sleepThread( 1/4 );
            System.out.println( Thread.currentThread().getName() +"\t\t\t\t\t « Instance :: "+ counter3);
        }
        public static void main(String[] args) throws InterruptedException {
            Runtime runtime = Runtime.getRuntime();
    
            int availableProcessors = runtime.availableProcessors();
            System.out.println("availableProcessors :: "+availableProcessors);
            System.out.println("MAX JVM will attempt to use : "+ runtime.maxMemory() / MegaBytes );
            System.out.println("JVM totalMemory also equals to initial heap size of JVM : "+ runtime.totalMemory() / MegaBytes );
            System.out.println("Returns the amount of free memory in the JVM : "+ untime.freeMemory() / MegaBytes );
            System.out.println(" ===== ----- ===== ");
    
            VolatileTest volatileTest = new VolatileTest();
            Thread t1 = new Thread( volatileTest );
            t1.start();
    
            Thread t2 = new Thread( volatileTest );
            t2.start();
    
            Thread t3 = new Thread( volatileTest );
            t3.start();
    
            Thread t4 = new Thread( volatileTest );
            t4.start();
    
            Thread.sleep( 10 );;
    
            Thread optimizeation = new Thread() {
                @Override public void run() {
                    System.out.println("Thread Start.");
    
                    Integer appendingVal = volatileTest.counter2 + volatileTest.counter2 + volatileTest.counter2;
    
                    System.out.println("End of Thread." + appendingVal);
                }
            };
            optimizeation.start();
        }
    
        public void sleepThread( long sec ) {
            try {
                Thread.sleep( sec * 1000 );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    

    Static[Class Field] vs Volatile[Instance Field] - Both are not cached by threads

    • Static fields are common to all threads and get stored in Method Area. Static with volatile no use. Static field cant be serialized.

    • Volatile mainly used with instance variable which get stored in heap area. The main use of volatile is to maintain updated value over all the Threads. instance volatile field can be Serialized.

    @see

    • Volatile Vs Static in java
    • System with multiple cores sharing an L2 cache
    • JVM memory model
    0 讨论(0)
  • 2020-11-28 20:28

    Ideally, if keepRunning wasn't volatile, thread should keep on running indefinitely. But, it does stop after few seconds.

    If you are running in a single-processor or if your system is very busy, the OS may be swapping out the threads which causes some levels of cache invalidation. Not having a volatile doesn't mean that memory will not be shared, but the JVM is trying to not synchronize memory if it can for performance reasons so the memory may not be updated.

    Another thing to note is that System.out.println(...) is synchronized because the underlying PrintStream does synchronization to stop overlapping output. So you are getting memory synchronization "for free" in the main-thread. This still doesn't explain why the reading loop sees the updates at all however.

    Whether the println(...) lines are in or out, your program spins for me under Java6 on a MacBook Pro with an Intel i7.

    Can anyone explain volatile with example ? Not with theory from JLS.

    I think your example is good. Not sure why it isn't working with all System.out.println(...) statements removed. It works for me.

    Is volatile substitute for synchronization ? Does it achieve atomicity ?

    In terms of memory synchronization, volatile throws up the same memory barriers as a synchronized block except that the volatile barrier is uni-directional versus bi-directional. volatile reads throw up a load-barrier while writes throw up a store-barrier. A synchronized block is a bi-directional barrier with the addition of mutex locking.

    In terms of atomicity, however, the answer is "it depends". If you are reading or writing a value from a field then volatile provides proper atomicity. However, incrementing a volatile field suffers from the limitation that ++ is actually 3 operations: read, increment, write. In that case or more complex mutex cases, a full synchronized block may be necessary. AtomicInteger solves the ++ issue with a complicated test-and-set spin-loop.

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

    Please find the solution below,

    The value of this variable will never be cached thread-locally: all reads and writes will go straight to "main memory". The volatile force the thread to update the original variable for each time.

    public class VolatileDemo {
    
        private static volatile int MY_INT = 0;
    
        public static void main(String[] args) {
    
            ChangeMaker changeMaker = new ChangeMaker();
            changeMaker.start();
    
            ChangeListener changeListener = new ChangeListener();
            changeListener.start();
    
        }
    
        static class ChangeMaker extends Thread {
    
            @Override
            public void run() {
                while (MY_INT < 5){
                    System.out.println("Incrementing MY_INT "+ ++MY_INT);
                    try{
                        Thread.sleep(1000);
                    }catch(InterruptedException exception) {
                        exception.printStackTrace();
                    }
                }
            }
        }
    
        static class ChangeListener extends Thread {
    
            int local_value = MY_INT;
    
            @Override
            public void run() {
                while ( MY_INT < 5){
                    if( local_value!= MY_INT){
                        System.out.println("Got Change for MY_INT "+ MY_INT);
                        local_value = MY_INT;
                    }
                }
            }
        }
    
    }
    

    Please refer this link http://java.dzone.com/articles/java-volatile-keyword-0 to get more clarity in it.

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

    Volatile --> Guarantees visibility and NOT atomicity

    Synchronization (Locking) --> Guarantees visibility and atomicity (if done properly)

    Volatile is not a substitute for synchronization

    Use volatile only when you are updating the reference and not performing some other operations on it.

    Example:

    volatile int i = 0;
    
    public void incrementI(){
       i++;
    }
    

    will not be thread safe without use of synchronization or AtomicInteger as incrementing is an compound operation.

    Why program does not run indefinitely?

    Well that depends on various circumstances. In most cases JVM is smart enough to flush the contents.

    Correct use of volatile discusses various possible uses of volatile. Using volatile correctly is tricky, I would say "When in doubt, Leave it out", use synchronized block instead.

    Also:

    synchronized block can be used in place of volatile but the inverse is not true.

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

    Lot's of great examples, but I just want to add that there are a number of scenarios where volatile is required so there is no one concrete example to rule them a.

    1. You can use volatile to force all threads to get latest value of the variable from main memory.
    2. You can use synchronization to guard critical data
    3. You can use Lock API
    4. You can use Atomic variables

    Check it out for more Java volatile examples.

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

    I have modified your example slightly. Now use the example with keepRunning as volatile and non volatile member :

    class TestVolatile extends Thread{
        //volatile
        boolean keepRunning = true;
    
        public void run() {
            long count=0;
            while (keepRunning) {
                count++;
            }
    
            System.out.println("Thread terminated." + count);
        }
    
        public static void main(String[] args) throws InterruptedException {
            TestVolatile t = new TestVolatile();
            t.start();
            Thread.sleep(1000);
            System.out.println("after sleeping in main");
            t.keepRunning = false;
            t.join();
            System.out.println("keepRunning set to " + t.keepRunning);
        }
    }
    
    0 讨论(0)
提交回复
热议问题