Java中 Volatile关键字
 
 
  Volatile关键字用于通过不同的线程修改变量的值。它还用于使类线程安全。这意味着多个线程可以同时使用类的方法和实例,而不会出现任何问题。 volatile关键字可以与原始类型或对象一起使用。
 
  volatile关键字不缓存变量的值,并且始终从主内存中读取变量。 volatile关键字不能与类或方法一起使用。但是,它与变量一起使用。它还保证可见性和顺序。它可以防止编译器对代码进行重新排序。 
 
 特定设备寄存器的内容可以随时更改,因此您需要volatile关键字,以确保编译器不会优化此类访问。
 
示例
 
 
  
   class Test
 {
     static int var=5;
 }
  
 
 
  
 在上面的示例中,假定两个线程在同一类上工作。两个线程都在不同的处理器上运行,其中每个线程都有其本地var副本。如果有任何线程修改其值,则更改将不会反映在主内存中的原始线程中。导致数据不一致,因为另一个线程不知道修改后的值。
 
 
  
   class Test
 {
     static volatile int var =5;
 }
  
 
 
  
 在上面的示例中,静态变量是在所有对象之间共享的类成员。主存储器中只有一个副本。 volatile变量的值永远不会存储在缓存中。所有读写操作都将在主内存中进行。
 
何时使用它?
 
如果要自动读写long和double变量,可以使用volatile变量。  
它可以用作Java中实现同步的另一种方法。 
完成读取操作后,所有读取器线程将看到volatile变量的更新值。如果您不使用volatile关键字,则不同的阅读器线程可能会看到不同的值。 
它用于通知编译器多个线程将访问特定的语句。这样可以防止编译器进行任何重新排序或任何优化。 
如果不使用易失性变量,编译器可以对代码重新排序,可以自由地写入易失性变量的缓存值,而不用从主存储器中读取。 
重要要点
 
您可以将volatile关键字与变量一起使用。在类和方法中使用volatile关键字是非法的。 
它保证volatile变量的值始终从主内存中读取,而不是从本地线程缓存中读取。 
如果您声明变量为volatile,则读写是原子的 
它降低了内存一致性错误的风险。 
任何对Java中的volatile变量的写操作都会在与该变量连续读取的关系建立之前发生。 
 volatile变量始终对其他线程可见。 
作为对象引用的volatile变量可以为null。 
在多个线程之间不共享变量时,不需要在该变量中使用volatile关键字。 
同步与volatile关键字之间的区别
 
  Volatile关键字不能替代synced关键字,但是在某些情况下可以用作替代。有以下区别如下: 
 
 
 
   
   | Volatile关键字 | Synchronization关键字 | 
 
   
   | Volatile关键字是字段修饰符。 | Synchronized关键字修改代码块和方法。 | 
 
   
   | 在发生波动的情况下,无法阻止线程等待。 | 在同步的情况下可以阻止线程等待。 | 
 
   
   | 它提高了线程性能。 | 同步方法会降低线程性能。 | 
 
   
   | 它一次在线程内存和主内存之间同步一个变量的值。 | 它在线程内存和主内存之间同步所有变量的值。 | 
 
   
   | 易失性字段不受编译器优化的影响。 | 同步需要进行编译器优化。 | 
 
 
 
易失关键字示例
 
 在下面的示例中,我们定义了一个增加计数器值的类。当线程开始执行时,VolatileThread.java中的run()方法将获取更新值和旧值。在主类中,我们定义线程的数组。
 
 
  VolatileData.java  
 
 
  
   public class VolatileData{
     private volatile int counter = 0;
     public int getCounter(){
         return counter;
     }
     public void increaseCounter() {
         ++counter;
     //increases the value of counter by 1 
     }
 }
  
 
 
  
 
  VolatileThread.java  
 
 
  
   VolatileThread.java
 public class VolatileThread extends Thread{
     private final VolatileData data;
     public VolatileThread(VolatileData data) {
         this.data = data;
     }
     @Override
 public void run(){
         int oldValue = data.getCounter();
         System.out.println("[Thread " + Thread.currentThread().getId() + "]: Old value = " + oldValue);
         data.increaseCounter();
         int newValue = data.getCounter();
         System.out.println("[Thread " + Thread.currentThread().getId() + "]: new value = " + newValue);
     }
 }
  
 
 
  
 
  VolatileMain.java  
 
 
  
   public class VolatileMain{
     private final static int noOfThreads = 2;
     public static void main(String[] args) throws InterruptedException{
         VolatileData volatileData = new VolatileData();
         //object of VolatileData class
         Thread[] threads = new Thread[noOfThreads];
         //creating Thread array 
         for(int i = 0;i <noOfThreads;++i)
             threads[i] = new VolatileThread(volatileData);
             for(int i = 0;i <noOfThreads;++i)
                 threads[i].start();
             //starts all reader threads
             for(int i = 0;i <noOfThreads;++i)
                 threads[i].join();
                 //wait for all threads
     }
 }
  
 
 
  
 
 输出:  
 
 
  
   [Thread 9]: Old value = 0
 [Thread 9]: new value = 1
 [Thread 10]: Old value = 1
 [Thread 10]: new value = 2