Java中volatile关键字的作用与用法详解

 更新时间:2016年09月29日 16:23:58   作者:11楼的日记  
volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情。这篇文章主要介绍了Java中volatile关键字的作用与用法详解的相关资料,需要的朋友可以参考下

volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在Java 5之后,volatile关键字才得以重获生机。

volatile 关键字作用是,使系统中所有线程对该关键字修饰的变量共享可见,可以禁止线程的工作内存对volatile修饰的变量进行缓存。

volatile 2个使用场景:

1.可见性:Java提供了volatile关键字来保证可见性。

  当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。

  而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。

  另外,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。

先看一段代码,假如线程1先执行,线程2后执行:

//线程1
boolean stop = false;
while(!stop){
doSomething();
}
//线程2
stop = true;

  这段代码是很典型的一段代码,很多人在中断线程时可能都会采用这种标记办法。但是事实上,这段代码会完全运行正确么?即一定会将线程中断么?不一定,也许在大多数时候,这个代码能够把线程中断,但是也有可能会导致无法中断线程(虽然这个可能性很小,但是只要一旦发生这种情况就会造成死循环了)。

  下面解释一下这段代码为何有可能导致无法中断线程。在前面已经解释过,每个线程在运行过程中都有自己的工作内存,那么线程1在运行的时候,会将stop变量的值拷贝一份放在自己的工作内存当中。

  那么当线程2更改了stop变量的值之后,但是还没来得及写入主存当中,线程2转去做其他事情了,那么线程1由于不知道线程2对stop变量的更改,因此还会一直循环下去。

  但是用volatile修饰之后就变得不一样了:

  第一:使用volatile关键字会强制将修改的值立即写入主存;

  第二:使用volatile关键字的话,当线程2进行修改时,会导致线程1的工作内存中缓存变量stop的缓存行无效(反映到硬件层的话,就是CPU的L1或者L2缓存中对应的缓存行无效);

  第三:由于线程1的工作内存中缓存变量stop的缓存行无效,所以线程1再次读取变量stop的值时会去主存读取。

  那么在线程2修改stop值时(当然这里包括2个操作,修改线程2工作内存中的值,然后将修改后的值写入内存),会使得线程1的工作内存中缓存变量stop的缓存行无效,然后线程1读取时,发现自己的缓存行无效,它会等待缓存行对应的主存地址被更新之后,然后去对应的主存读取最新的值。

  那么线程1读取到的就是最新的正确的值。

2.保证有序性

volatile boolean inited = false;
//线程1:
context = loadContext(); 
inited = true; 
//线程2:
while(!inited ){
sleep()
}
doSomethingwithconfig(context);

确保context已经初始化完成。

3.double check

class Singleton{
private volatile static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if(instance==null) {
synchronized (Singleton.class) {
if(instance==null)
instance = new Singleton();
}
}
return instance;
}
}

以上所述是小编给大家介绍的Java中volatile关键字的作用与用法详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

相关文章

  • Java LinkedHashMap 底层实现原理分析

    Java LinkedHashMap 底层实现原理分析

    LinkedHashMap继承自HashMap实现了Map接口。基本实现同HashMap一样,不同之处在于LinkedHashMap保证了迭代的有序性。其内部维护了一个双向链表,解决了 HashMap不能随时保持遍历顺序和插入顺序一致的问题。
    2021-05-05
  • java封装的概念和实现方法示例

    java封装的概念和实现方法示例

    这篇文章主要介绍了java封装的概念和实现方法,结合实例形式详细分析了java封装的概念、原理及相关使用技巧,需要的朋友可以参考下
    2019-11-11
  • Java求字符串长度的方法举例

    Java求字符串长度的方法举例

    这篇文章主要给大家介绍了关于Java求字符串长度的相关资料,Java中的字符串是一种常见的数据类型,用于表示文本数据,文中给出了详细的代码实例,需要的朋友可以参考下
    2023-10-10
  • java版飞机大战实战项目详细步骤

    java版飞机大战实战项目详细步骤

    这篇文章主要为大家详细介绍了java版飞机大战实战项目详细步骤,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • 详解springMVC之与json数据交互方法

    详解springMVC之与json数据交互方法

    本篇文章主要介绍了详解springMVC之与json数据交互方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • 深入浅出重构Mybatis与Spring集成的SqlSessionFactoryBean(上)

    深入浅出重构Mybatis与Spring集成的SqlSessionFactoryBean(上)

    通常来讲,重构是指不改变功能的情况下优化代码,但本文所说的重构也包括了添加功能。这篇文章主要介绍了重构Mybatis与Spring集成的SqlSessionFactoryBean(上)的相关资料,需要的朋友可以参考下
    2016-11-11
  • SpringBoot使用@ControllerAdvice全局异常处理

    SpringBoot使用@ControllerAdvice全局异常处理

    这篇文章主要介绍了SpringBoot使用@ControllerAdvice全局异常处理,异常处理是非常重要的一部分,它可以帮助我们捕获并处理应用程序中出现的异常情况,提高应用程序的健壮性和可靠性,需要的朋友可以参考下
    2023-07-07
  • 详解Java并发编程中的优先级队列PriorityBlockingQueue

    详解Java并发编程中的优先级队列PriorityBlockingQueue

    PriorityBlockingQueue是Java中实现了堆数据结构的线程安全的有界阻塞队列。本文将会深入解读PriorityBlockingQueue的源码实现,感兴趣的可以了解一下
    2023-05-05
  • java使用poi读取ppt文件和poi读取excel、word示例

    java使用poi读取ppt文件和poi读取excel、word示例

    这篇文章主要介绍了java使用poi读取ppt文件和poi读取excel、word示例,需要的朋友可以参考下
    2014-03-03
  • Java多线程中的wait与notify方法详解

    Java多线程中的wait与notify方法详解

    这篇文章主要介绍了Java多线程中的wait与notify方法详解,线程的调度是无序的,但有些情况要求线程的执行是有序的,因此,我们可以使用 wait() 方法来使线程执行有序,需要的朋友可以参考下
    2023-08-08

最新评论