当前位置: 首页 > 编程笔记 >

解析java中volatile关键字

翟丰茂
2023-03-14
本文向大家介绍解析java中volatile关键字,包括了解析java中volatile关键字的使用技巧和注意事项,需要的朋友参考一下

在java多线程编程中经常volatile,有时候这个关键字和synchronized 或者lock经常有人混淆,具体解析如下:
在多线程的环境中会存在成员变量可见性问题: java的每个线程都存在一个线程栈的内存空间,该内存空间保存了该线程运行时的变量信息,当线程访问某一个变量值的时候首先会根据这个变量的地址找到对象的堆内存或者是栈堆存(原生数据类型)中的具体的内容,然后把这个内同赋值一个副本保存在本线程的线程栈中,紧接着对这个变量的一切操作在线程完成退出之前都和堆栈内存中的变量内容是没有关系的,操作的是自己线程栈中的副本。当操作完后会把操作完的结果写回到主内存中。假如有两个线程A和B,同事操作某一个变量x;A对x进行了加1操作,那么B获取的副本可能是x加1后的结果,也可能是x;为了保证获取内存中最新的数据变量 需要加上 volatile 关键字,这样在每次对x进行操作的时候都会去检查下线程栈中的变量的值是不是和住内存中变量的值一样,如果不一样会重新load。
eg:

public class ThreadSee { 
//t1线程会根据flag的值做对应的操作,主线程会更改t1的值 
 public static void main(String[] args) throws InterruptedException { 
    ThReadTest th= new ThReadTest(); 
    Thread t1 = new Thread(th); 
    t1.start(); 
    Thread.sleep(1000); 
    th.changeFlag(); 
    Thread.sleep(2000); 
    System.out.println(th.getFlag()); 
  } 
 
} 
 
 
class ThReadTest implements Runnable{ 
 
  //线程访问变量时会把其load到对应的线程栈中,每次操作时都要获取内存中最新的数据 
  private volatile boolean stopflag; 
  @Override 
  public void run() { 
    int i=0; 
    while(!stopflag){ 
      i++; 
      System.out.println("=="+Thread.currentThread().getName()); 
    } 
    System.out.println("Thread finish:"+i); 
  } 
  public void changeFlag(){ 
    this.stopflag=true; 
    System.out.println(Thread.currentThread().getName()+"***********"); 
  } 
 
  public boolean getFlag(){ 
    return stopflag; 
  } 
} 

上述代码如果去掉volatile,会一直死循环执行下去。
但是volatile不能保证线程安全的同步
eg:

public class ThreadSave implements Runnable{ 
  static ThreadSave sync = new ThreadSave(); 
  static volatile int j=0; 
  //Lock lock =new ReentrantLock(); 
  public void inscane(){ 
    // lock.lock(); 
    for(int i=0;i<10000000;i++){ 
      j++; 
    } 
   //  lock.unlock(); 
  } 
  @Override 
  public void run() { 
    inscane(); 
  } 
  public static void main(String[] args) throws InterruptedException { 
    Thread t1 = new Thread(sync); 
    Thread t2 = new Thread(sync); 
    t1.start(); 
    t2.start(); 
    t1.join(); 
    t2.join(); 
    System.out.println(j); 
  } 
} 

根据上述代码执行的结果不是预期20000000,
因为对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的。
例如假如线程1,线程2 在进行线程栈与主内存read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值
在线程1堆count进行修改之后,会write到主内存中,主内存中的count变量就会变为6;
线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6;
导致两个线程及时用volatile关键字修改之后,还是会存在并发的情况。
综上所述:
volatile只会保证线程去做一个检查当前线程栈的变量值和主内存中数据值是否一样的这么一个动作,只此而已。而lock或者是synchronized 会保证某一时刻只有单个线程进入该方法,从而确保其线程安全性。
所以在如果多个线程去修改一个volatile变量那么没有实际的逻辑意义。如果一个线程去修改其他的线程依赖修改的变量值,此时是有作用的。

以上就是本文的全部内容,希望对大家的学习有所帮助。

 类似资料:
  • 我知道关于volatile有很多问题,但我只是被讨论搞糊涂了:Java:volatile如何保证这段代码中“数据”的可见性? 我读过的每个网站都说可以在缓存中存储一个变量(使这个值对于其他线程不可见),我甚至发现了这个例子https://dzone.com/articles/java-volatile-keyword-0 所以我的第一个问题是:Java是否在缓存中存储变量值(在哪个缓存中?l1 l

  • 本文向大家介绍Java中的volatile关键字,包括了Java中的volatile关键字的使用技巧和注意事项,需要的朋友参考一下 volatile修饰符用于让JVM知道访问该变量的线程必须始终将其自身的变量私有副本与内存中的主副本合并。 访问易失性变量将同步所有在主存储器中缓存的变量副本。可变变量只能应用于对象类型或私有类型的实例变量。易失性对象引用可以为null。 示例

  • 本文向大家介绍Java并发编程:volatile关键字详细解析,包括了Java并发编程:volatile关键字详细解析的使用技巧和注意事项,需要的朋友参考一下 volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在Java 5之后,volatile关键字才得以重获生机。 volatile关键字虽然从

  • 本文向大家介绍谈谈Java中Volatile关键字的理解,包括了谈谈Java中Volatile关键字的理解的使用技巧和注意事项,需要的朋友参考一下 volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在Java 5之后,volatile关键字才得以重获生机。volatile关键字虽然从字面上理解起来

  • 问题内容: 今天的工作中,我遇到了volatileJava中的关键字。不太熟悉,我发现了以下解释: Java理论与实践:管理波动 鉴于该文章详细解释了所讨论的关键字,您是否曾经使用过它,或者是否曾经遇到过可以正确使用此关键字的情况? 问题答案: volatile具有内存可见性的语义。基本上,字段的值对所有读取器(尤其是其他线程)在写入操作完成后变为可见。没有,读者可能会看到一些未更新的值。 回答你

  • 原文链接:http://www.cnblogs.com/dolphin0520/p/3920373.html volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在Java 5之后,volatile关键字才得以重获生机。 volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事