全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

volatile可见性的一些认识和论证

一、前言

    volatile的关键词的使用在JVM内存模型中已是老生常谈了,这篇文章主要结合自己对可见性的一些认识和一些直观的例子来谈谈volatile。文章正文大致分为三部分,首先会介绍一下happen-before,接着讲解volatile的一些使用场景,最后会附上一些例子来论证使用与不使用volatile的区别。

二、happen-before

    对操作系统有认识的同学一定知道,CPU一般有三级缓存,在与内存交互的时候,存在缓存与内存的更新问题,其次CPU在读取指令的时候,会做一些指令重排序的工作,提高程序运行效率。类比JVM内存模型(见下图),每个线程拥有自己的工作内存,同时存在一个主存,线程间通过主存来进行通信,同样的,JVM也存在指令重排序,可见JVM内存模型与实际物理内存模型十分相似。(这里顺便提一下,编译器其实也会作一定重排序优化)。

    作为开发人员,你不可能了解到每个JVM优化细节,更不可能了解到CPU何时会进行指令重排序,所以java语言定义了更上层的一个概念,就是"happen-before"。起初,我看到这个单词的时候,误以为这是一个指令执行顺序的规则,后来仔细想想又发觉不对劲。如果”happen-before“仅仅是抽象了指令执行顺序的概念,那么它就把握不了“工作内存将值写回主存”和“工作内存从主存中刷新自己的值”这个两个action的时机。那么这个概念也就变得没什么意义了。所以!所以!所以!”happen-before“是一个可见性的原则!!!

下面给出happen-before的具体规则:

程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;

锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作;

volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作;

传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;

线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;

线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;

线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;

对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始;

三、volatile的使用场景

    happen-before的第三条规则提到“volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作”,也就是说;一个volatile变量的写操作对后续对读操作可见。说白了就是每次写完volatile变量,都会将值从工作内存写回到主存中去,每次读取volatile变量,工作内存必须从主存中刷新下自己的值。如此的话,volatile就是为了解决多个线程共享数据的可见性问题。但是不是任何数据共享场景都可以使用volatile,必须满足以下两种情景才行。

    应用场景:

    1.多个线程不依赖原值的情况下进行读写操作

    2.一个线程依赖原值进行写操作,多个线程进行读操作

在我看来,除了这两种情况外,无非是多个线程依赖原值进行运算,这样子倒不是说volatile可见性不起作用了,而是无法保证读取原值和运算是一个原子操作!举个简单的例子,多个线程执行i++;i是一个共享变量,由于读取i的值和i自增不是一个原子操作,所以i最终会丢失掉一部分自增过程。代码如下,最终i输出的结果是一个小于1000的整数。

/**
 * Created by chenqimiao on 17/8/23.
 */
public class Testv {
  public static volatile int i = 0;
  public static void main(String args[]){
    for (int i =0;i<1000;i++){
      new Thread(){
        public void run(){
          Thread.yield();
          Testv.i++;
        }
      }.start();
    }
    System.out.println(Testv.i);
  }
}

要满足以上这种需求,我们还必须赋予代码原子性,最常用的肯定是锁操作了,一个字稳,性能可观,同时保证原子性和可见性。如果想操作一波的话,还可以考虑使用一些无锁操作,如CAS,象java.util.concurrent包下的一些原子类就是利用了CAS来做到原子性,但原子性并不能保证可见性,这个时候,还需要配合volatile。

以上种种都是对volatile使用场景的概括,想了解具体的使用场景可以参考博文:https://www.ibm.com/developerworks/cn/java/j-jtp06197.html

四、volatile可见性的证明

   先上段代码好了,不知道从何说起了。

package com.example.demo.netty;
/**
 * Created with IntelliJ IDEA.
 * User: chenqimiao
 * Date: 2017/8/23
 * Time: 9:16
 * To change this template use File | Settings | File Templates.
 */
public class VolatileTest {
   boolean isStop = false;
  public void test(){
    Thread t1 = new Thread(){
      public void run() {
        isStop=true;
      }
    };
    Thread t2 = new Thread(){
      public void run() {
        while (!isStop);
      }
    };
    t2.start();
    t1.start();
  }
  public static void main(String args[]) throws InterruptedException {
    for (int i =0;i<25;i++){
      new VolatileTest().test();
    }
  }
}

    上面这段代码可能永远也不会结束,因为线程一对isStop的赋值,线程二可能对此并不可见。当然只是可能,所以为了放大可见性问题,我这里作了25次循环。只要有一组线程,“线程一对isStop的赋值,线程二对此不可见”的情况发生,就不会退出程序。

    now,假如你给 isStop 添加一个 volatile 关键字,那么你会发现程序立马就会退出。

总结

以上所述是小编给大家介绍的volatile可见性的一些认识和论证,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!


# volatile  # 可见性  # java  # java并发编程关键字volatile保证可见性不保证原子性详解  # Java并发volatile可见性的验证实现  # 通过volatile验证线程之间的可见性  # Java并发编程-volatile可见性详解  # volatile保证可见性及重排序方法  # 关键词  # 多个  # 是一个  # 自己的  # 见性  # 原值  # 作了  # 小编  # 性问题  # 检测到  # 都是  # 对此  # 就会  # 好了  # 也会  # 还可以  # 也就  # 子类  # 在此  # 老生常谈 


相关文章: 建站之星如何通过成品分离优化网站效率?  高防服务器:AI智能防御DDoS攻击与数据安全保障  儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?  整人网站在线制作软件,整蛊网站退不出去必须要打我是白痴才能出去?  建站之星代理费用多少?最新价格详情介绍  青浦网站制作公司有哪些,苹果官网发货地是哪里?  寿县云建站:智能SEO优化与多行业模板快速上线指南  建站主机如何选?高性价比方案全解析  武汉网站制作费用多少,在武汉武昌,建面100平方左右的房子,想装暖气片,费用大概是多少啊?  如何高效配置香港服务器实现快速建站?  北京制作网站的公司排名,北京三快科技有限公司是做什么?北京三快科技?  如何通过VPS建站无需域名直接访问?  建站一年半SEO优化实战指南:核心词挖掘与长尾流量提升策略  定制建站哪家更专业可靠?推荐榜单揭晓  成都品牌网站制作公司,成都营业执照年报网上怎么办理?  小建面朝正北,A点实际方位是否存在偏差?  建站之星安装后如何自定义网站颜色与字体?  电商网站制作公司有哪些,1688网是什么意思?  建站之星安装路径如何正确选择及配置?  如何配置IIS站点权限与局域网访问?  宝塔新建站点报错如何解决?  建站主机是什么?如何选择适合的建站主机?  TestNG的testng.xml配置文件怎么写  建站之星客服服务时间及联系方式如何?  韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南  保定网站制作方案定制,保定招聘的渠道有哪些?找工作的人一般都去哪里看招聘信息?  css网站制作参考文献有哪些,易聊怎么注册?  淘宝制作网站有哪些,淘宝网官网主页?  实例解析Array和String方法  如何选择高效稳定的ISP建站解决方案?  利用JavaScript实现拖拽改变元素大小  如何用搬瓦工VPS快速搭建个人网站?  seo网站制作优化,网站SEO优化步骤有哪些?  建站之星备案是否影响网站上线时间?  如何快速生成ASP一键建站模板并优化安全性?  电商平台网站制作流程,电商网站如何制作?  济南专业网站制作公司,济南信息工程学校怎么样?  C++中的Pimpl idiom是什么,有什么好处?(隐藏实现)  高防服务器租用指南:配置选择与快速部署攻略  PHP正则匹配日期和时间(时间戳转换)的实例代码  如何配置FTP站点权限与安全设置?  如何快速登录WAP自助建站平台?  高防网站服务器:DDoS防御与BGP线路的AI智能防护方案  如何用AWS免费套餐快速搭建高效网站?  如何在橙子建站上传落地页?操作指南详解  如何快速搭建二级域名独立网站?  专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?  如何获取免费开源的自助建站系统源码?  如何在阿里云虚拟主机上快速搭建个人网站?  黑客入侵网站服务器的常见手法有哪些? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。