The simplest and most clear example of a volatile keyword in Java

I read about the volatile keyword in Java and fully understand its theoretical part.

But I'm looking for a good example that shows what would happen if the variable were not mutable and would be.

The code snippet below does not work properly (taken from here ):

class Test extends Thread { boolean keepRunning = true; public void run() { while (keepRunning) { } System.out.println("Thread terminated."); } public static void main(String[] args) throws InterruptedException { Test t = new Test(); t.start(); Thread.sleep(1000); t.keepRunning = false; System.out.println("keepRunning set to false."); } } 

Ideally, if keepRunning not volatile, the thread should run indefinitely. But he stops after a few seconds.

I have two main questions:

  • Can anyone explain the variability with an example? Not with the theory from JLS.
  • Is volatile synchronization substitute? Does it achieve atomicity?
+69
java multithreading concurrency volatile
Jul 19 '13 at 14:02
source share
13 answers

Volatile β†’ Ensures visibility and NOT atomicity

Synchronization (blocking) β†’ guarantees visibility and atomicity (if performed correctly)

Volatile does not replace synchronization

Use volatile only when you update the link and do not perform some other operations on it.

Example:

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

It will not be thread safe without using synchronization or AtomicInteger, since incrementing is a composite operation.

Why the program does not start endlessly?

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

Proper use of volatile discusses various possible uses for volatile. Using volatile correctly is difficult, I would say, "If in doubt, leave this alone," use a synchronized block instead.

also:

a synchronized block can be used instead of volatile, but the inversion is not true .

+47
Jul 19 '13 at 14:07
source share

For your specific example: if volatile is not declared, the server-side JVM can take the keepRunning variable keepRunning of the loop because it is not changed in the loop (turning it into an infinite loop), but the client JVM will not. That is why you see different results.

The following is a general explanation of volatile variables:

When a field is declared volatile , the compiler and runtime are notified that this variable is shared and that its operations 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 reading a volatile variable always returns the most recent record by any thread .

The effects of the visibility of variable variables go beyond the value of the variable itself. When stream A writes to volatile and subsequently stream B reads the same variable, the values ​​of all the variables that were visible to A before writing to volatile become visible to B after reading volatile.

The most commonly used variables change as a completion, interrupt, or state flag:

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

Volatile variables can be used for other types of state information, but more attention is required when trying to do 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 from only one stream.

Blocking can guarantee both visibility and atomicity; mutable variables can only guarantee visibility.

You can use variable variables only if all of the following criteria are met:

  • Writing to a variable does not depend on its current value, or you can make sure that only one thread updates the value;
  • The variable does not participate in invariants with other state variables; and
  • Locking is not required for any other reason when accessing a variable.

Debugging tip : -server sure to specify the JVM -server command line -server when invoking the JVM, even for development and testing. The server-side JVM performs more optimization than the client JVM, for example, the output of variables from a loop that have not been changed in the loop; code that can run in a development environment (client JVM) may break in a deployment environment (JVM server).

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

+27
Jul 19. '13 at 14:24
source share

I changed your example a bit. Now use the keepRunning example as a 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); } } 
+13
Jan 05 '14 at 10:02
source share

What is the volatile keyword?

volatile prevents caching of variables .

Consider the code, first without the 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 the RETURN key button is pressed. But in some machines may happen that the variable works equal to cached , and you cannot change its value from the shutdown () method, which leads to infinite printing of the welcome text.

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

 private volatile boolean running = true; //volatile keyword 

Thus, using the volatile keyword is good and safer programming practice .

+11
Jul 18 '15 at 20:08
source share

Variable Volatile : The volatile keyword applies to variables. The volatile keyword in Java ensures that the value of the volatile variable is always read from main memory, and not from the local stream cache.

 Access_Modifier volatile DataType Variable_Name; 

Volatile Field: An indication for the VM that multiple threads may try to access / update the field value at the same time. A special kind of instance variable that should be used by all threads with a modified value. Like the Static (Class) variable, only one copy of the volatile value is cached in the main memory, so before performing any ALU operations, each thread must read the updated value from the main memory, after the ALU operation, it must write to the main memory directive. (Writing to volatile variable v is synchronized with all subsequent readings of v by any thread) This means that changes in the volatile variable are always visible to other threads.

enter image description here

Here to nonvoltaile variable , if thread t1 changes the value in cache t1, thread t2 cannot access the changed value until t1 is written, and t2 does not read the last changed value from the main memory, which can 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 : A 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 dynamic memory.

Synchronization : synchronized is applicable to methods, blocks. allows you to perform only 1 thread at a time. If t1 takes control, then the rest of the threads must wait until it releases 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 are stored in the method area. Static with volatile useless. A static field cannot be serialized.

  • Volatile is mainly used with an instance variable that is stored in the heap area. The main use of volatile is to maintain an updated value for all threads. a mutable instance field can be serialized .

@see

+6
Dec 07 '17 at 13:02 on
source share

Ideally, if keepRunning is not mutable, the thread should continue to run indefinitely. But it stops after a few seconds.

If you are working in uniprocessor mode or your system is very busy, the OS can unload threads, which causes some levels of cache invalidation. As others have already mentioned, the absence of volatile does not mean that the memory will not be shared, but the JVM tries not to synchronize the memory, if possible for performance reasons, so the memory may not be updated.

It should also be noted that System.out.println(...) synchronized because the underlying PrintStream performs synchronization to stop overlapping output. Thus, you get memory synchronization β€œfor free” in the main thread. This still does not explain why the reading cycle even sees updates.

Regardless of whether println(...) strings are included, your program rotates for me under Java6 on a MacBook Pro with Intel i7.

Can anyone explain the variability with an example? Not with the theory from JLS.

I think your example is good. Not sure why it doesn't work with all remote System.out.println(...) operators. It works for me.

Is volatile synchronization substitute? Does it achieve atomicity?

In terms of memory synchronization, volatile throws the same memory barriers as the synchronized block, except that the volatile barrier is unidirectional rather than bidirectional. volatile reads create a load barrier and write reads create a store barrier. synchronized block is a bi-directional barrier.

In terms of atomicity , however, the answer is "it depends." If you are reading or writing a value from a field, volatile ensures the correct atomicity. However, the increment of the volatile field suffers from the restriction that ++ actually has 3 operations: read, increase, write. In this case, or in more complex cases of the mutex, a full synchronized block may be required.

+5
Jul 19 '13 at 14:04 on
source share

When a variable is volatile , this ensures that it will not be cached and that different threads will see the updated value. However, the absence of volatile marking does not guarantee the opposite. volatile was one of those things that have been broken in the JVM over time and are still not always well understood.

+3
Jul 19 '13 at 14:05
source share

volatile will not necessarily create gigantic changes, depending on the JVM and compiler. However, for many (extreme) cases there may be a difference between optimizations, as a result of which variable changes cannot be seen, but not written correctly.

In principle, the optimizer can choose to transfer non-volatile variables to registers or to the stack. If another thread changes them in the heap or class primitives, the other thread will continue to search for it on the stack, and it will become obsolete.

volatile ensures that this optimization does not happen, and all reads and writes will be directly in the heap or in another place where all threads will see.

+2
Jul 19 '13 at 14:05
source share

Please find the solution below.

The value of this variable will never be cached by the thread-locally: all reads and writes will go directly to the "main memory". Volatility causes the thread to update the original variable 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 to this link http://java.dzone.com/articles/java-volatile-keyword-0 to get more clarity in it.

+1
28 Oct. '14 at 1:43 on
source share

if you declare a variable as mutable, then it will not be stored in the local cache. Whenever a stream updates values, it updates to main memory. Thus, other threads can access the updated value.

+1
Apr 22 '15 at 7:23
source share

The volatile keyword tells the JVM that it can be modified by another thread. Each thread has its own stack and, therefore, its own copy of the variables that it can access. When a thread is created, it copies the value of all available 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 this example with and without volatile.

+1
Feb 08 '19 at 6:31
source share

Objects declared as volatile are commonly used to pass state information between threads. In order to ensure that the CPU cache is updated, that is, stored in synchronization, if there are variable fields, the CPU instruction, memory barrier, often called membar or fence, is emitted to update the CPU cache with a change in the value of the variable fields.

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

A mutable variable should only be used in the context of a stream. see example here

0
Oct 28 '13 at 19:49
source share

There are many good examples, but I just want to add that there are a number of scenarios where volatile is required, so there is no one specific example to manage them a.

  1. You can use volatile to force all threads to get the last value of a variable from main memory.
  2. You can use synchronization to protect sensitive data.
  3. You can use Lock API
  4. You can use Atomic variables

Check out other volatile Java examples .

0
Aug 05 '19 at 20:57 on
source share



All Articles