java多线程之volatile讲解

java多线程之volatile讲解

   最近一直在看多线程的一些知识,看了一些书和一些博客,收获还是挺多的,最近看了《java并发编程的艺术》这本书感觉收获很大也推荐给各位,同时也结合以前看的博客就好好的总结一下自己所学的东西吧,有不足的地方欢迎各位指正,这篇文章主要是讲volatile关键字的知识。

volatile的特性

  • 可见性:volatile在多线程中能够保证共享变量的“可见性”,简单的说就是当一个线程修改了volatile变量的时候,java线程内存模型能够确保所有的线程看到的这个变量的值是一致的。
  • 防止指令重排序

java内存模型

  • 在学习volatile的知识之前我们先来简单了解下java内存模型(JMM)引用一张网上很经典的表示java内存模型的图

  • 大概解释下这个图的意思
    • 在多个线程运行的时候每一个线程(Thread)都有一个属于自己的内存空间
    • 多个线程共同使用一个主存
    • 每个线程在对数据进行修改之前都会先在主存里面获取相关数据,然后在自己的工作内存里面对数据进行操作。

      可见性

      关键的地方就来了,因为每个线程然都是在自己的内存里进行操作,然而每个线程的工作内存之间都是相互不可见的,所以对共享变量的修改并不会马上被其他线程看到,所以就会造成多个线程操作同一个数据但是最后结果并不是我们期望的结果。当线程1去首先从主存中加载一个volatile变量到自己的工作内,然后对这个volatile变量进行写操作,写入操作结束之后,volatile变量的最新值会立马刷新到主内存,同时其他线程中的这个volatile变量会立马失效,会被强迫从主内存中重新读取volatile变量的最新值,这就是volatile变量的可见性实现的过程。同时这也可以看做是一个线程和其他线程通信的一个过程。

      防止指令重排序

      简单解释下指令重排序,重排序指的是编译器和处理器为了优化程序的性能会对指令序列进行重新排序的一种手段。在单线程的程序里,指令的重排序会保证执行结果的正确性,但是在多线程中指令的重排序对程序的执行结果的正确性就得不到保障(指令重排序的一些规则各位可以去查阅一下,这里不赘述)。volatile变量防止指令重排序指的就是一个volatile变量的写前面的对其他变量的读写操作会禁止与volatile变量写操作重排序(这个操作的是通过内存屏障来实现的,内存屏障的概述请看文章后面部分)概括下就是volatile读写的前后的指令不会被前后重排,但是前面跟后面的每个部分不保证执行顺序,同时前面的部分先于后面的部分加载到内存。(其实synchronized也对指令的重排序有一些限制,在后面我会写一篇讲解synchronized的博文会详细讲解一下,欢迎各位阅读)

内存屏障

JMM把内存屏障分为四类(摘自Java并发编程艺术)

volatile的应用

很多博客中基本上都说了volatile变量一般运用于不依附当前值的操作,比如自增,我的理解是这样的,如果volatile变量进行依附当前操作的值的运算,那么就会涉及到读volatile变量和写volatile变量这两个操作,volatile变量的读操作(从主内存读取到线程的工作内存)和写操作(将变量写到主内存中去)时,这两个组合起来的操作就是一个非原子性的操作,所以这种情况下使用volatile关键字就不合适,对于基本变量的一些非原子性操作(如自增)可以考虑使用java.util.concurrent.atomic包下的一些类,或者使用锁来进行。volatile变量一般用作比如一个标志变量这种单个读写的操作。
附上个人觉得volatile变量应用的一个讲得比较好的博客(https://www.ibm.com/developerworks/cn/java/j-jtp06197.html
同时各位也可以去看一下另外一篇讲解volatile的博文,同样比较棒(http://kwsir.cn/2017/10/12/Java%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B-volatile%E5%8F%AF%E8%A7%81%E6%80%A7%E7%9A%84%E4%BB%8B%E7%BB%8D/)。

写在最后

鉴于本人水平有限,所以如果文章中有不对的地方,十分欢迎各位在评论留言指点,或者发送到本人的qq邮箱[email protected]通知一下本人。谢谢大家。

猜你喜欢

转载自www.cnblogs.com/NewHongjay/p/9032240.html