volatile是jvm提供的轻量级的同步机制

  1. 保证可见性(一个线程的修改对其它线程是可见的)

  2. 不保证原子性

  3. 禁止指令重排序

    什么是指令重排?

    计算机在执行程序时,为了提高性能,编译器和处理器会对指令做重排,过程如下

    源代码--》编译器优化的重排--》指令并行的重排--》内存系统的重排--》最终执行的指令

    处理器在进行重排时必须考虑数据之间的依赖性

    单线程环境下重拍后执行的结果与代码顺序执行的结果一致

    多线程环境下线程交替进行,由于编译器优化重排的存在,两个线程使用的变量能否保证一致性无法确定

              /**
    * 如果有两个线程
    * 一个执行fun1,一个执行fun2
    * 1. 当fun1中语句一和语句二执行时发生指令重排,语句二在语句一之前执行
    * 那么语句二执行完后,没等语句一执行,fun2中执行,a=5
    * 2. 语句一先执行时,最后a=6
    * 所以多线程环境下,由于编译器的优化重排,结果不确定
    * <p>
    * volatile会禁止指令重排,让执行顺序按照代码编写的顺序执行
    */
    class ResortedDemo {
    int a;
    boolean flag; public void fun1() {
    a = 1;//语句一
    flag = true;//语句二
    } public void fun2() {
    if (flag) {
    a = a + 5;
    System.out.println(a);
    }
    }
    }

JMM(java memory model)java内存模型

jmm本身是一种抽象的概念,并不真实存在,它描述的是一组规范,通过这组字段定义了程序中各个变量(包括程序字段,静态字段和构成数组对象的元素)的访问方式

JMM关于同步的规定

  1. 线程加锁前,必须读取主内存的最新值到自己的工作内存
  2. 线程解锁前,必须把共享变量的值刷新回主内存
  3. 加锁解锁是同一把锁

由于JVM运行程序的实体是线程, 每个线程创建时JVM都会为其分配一个工作内存

线程对变量的操作必须在工作内存进行,首先将变量从主内存拷贝到自己的工作内存空间,然后对变量进行操作,然后再将变量写回到主内存

不能直接操作主内存的变量,线程之间不能访问其它线程的工作内存,因此线程间的通信(传值)必须通过主内存完成

volatile代码实例

/**
* # 验证volatile的可见性(每次读取都直接从主内存读取)
* 假设number=0;
* 1. number前面没有volatile,没有可见性
* 就算第一个线程更改了number的值,并写回了主内存,但由于没有可见性
* main线程并不知道已经修改,所以main线程中number一直等于0,一直在while循环中
* 2. number前面加上volatile,保证可见性
* 第一个线程更改完值并写回主内存后,由于number的可见性,
* main线程中立刻就能读取到主内存中number的修改,跳出while循环
* # 验证volatile不保证原子性
* 1. 原子性是什么意思
* 不可分割,完整性,也就是某个线程正在做某个具体业务时中间不可以被加塞或者被分割,
* 其它线程不能对该线程获取的资源进行任何操作(包括读取)
* 要么同时成功,要么同时失败
* 2.如何验证:
* 创建20个线程,每个线程对number做1000次加一操作,若最后number=20*1000,则有原子性,反之则没有
* <p>
* 经运行程序,number<20000,所以volatile不保证原子性
* <p>
* 3. 为什么不保证原子性
* number++:分为三步骤
* 1. 从主内存取值
* 2. 对值操作加1
* 3. 写回主内存
* <p>
* 多个线程同时读取到之内存中number的值,并操作加1,
* 最后把值写回主内存过程中,可能会出现数据丢失写值的效果
* 4. 如何解决原子性
* 1. 加sync
* 2. 使用juc包下的AtomicInteger
* 使用juc包下的AtomicInteger中CAS通过在将值写入主内存时循环比较的方式保证原子性
*/
public class VolatileDemo {
public static void main(String[] args) { A a = new A(); for (int i = 0; i < 20; i++) {
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
//测试volatile修饰的变量,不保证原子性
a.number++;
//测试AtomicInteger解决原子性
a.atomicInteger.getAndIncrement();
}
}, "线程" + i).start();
}
//需要等待上面20个线程运行结束,才能运行主线程
//后台有两个默认线程,所以大于2
while (Thread.activeCount() > 2) { //让当前线程获得可运行状态
Thread.yield();
} System.out.println(Thread.currentThread().getName() + "number=" + a.number); System.out.println(a.atomicInteger.get());
} public static void verifyVisible() {
A a = new A();
//第一个线程
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "start");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
a.change();
System.out.println(Thread.currentThread().getName() + "end:" + a.number); }).start(); //第二个线程
while (a.number == 0) {
//main线程一直在这里循环,如果a.number一直等于0,也就是没有可见性
//如果跳出了循环,就代表可见性触发了
} System.out.println(Thread.currentThread().getName() + "end:" + a.number);
}
} class A {
volatile int number = 0;
AtomicInteger atomicInteger = new AtomicInteger(0); public void change() {
number = 26;
}
}

volatile相关内容的更多相关文章

  1. linux用户权限相关内容查看

    linux用户权限相关内容查看 1   用户信息 创建用户一个名为 webuser 的账号,并填写相应的信息: root@iZ94fabhqhuZ:~# adduser webuser Adding ...

  2. SharePoint安全 - 在Goolge和Bing中查找SharePoint相关内容

    博客地址 http://blog.csdn.net/foxdave 本篇提供两个查询串字典,分别对应Google和Bing的搜索,用来查询SharePoint网站的相关内容 Google ShareP ...

  3. 韩顺平细说Servlet视频系列之tom相关内容

    韩顺平细说Servlet视频系列之tom相关内容 tomcat部署项目操作(注意:6.0版本以后的支持该操作,5.x版本需要另外配置?待验证!) 项目发布到tomcat的webapps文件下,然后启动 ...

  4. jQuery实现页内查找相关内容

    当需要在页面中查找某个关键字时,一是可以通过浏览器的查找功能实现,二是可以通过前端脚本准确查找定位,本文介绍通过jQuery实现的页面内容查找定位的功能,并可扩展显示查找后的相关信息. 本文以查找车站 ...

  5. Struts2(四)——页面相关内容

    上篇博客总结了数据流转各个方面的内容,这篇重点说一下框架对于界面上知识. 一,说到页面,记得在总体介绍中,说到Struts2比Struts1的一方面优势就是它支持更多的视图技术(Freemarker, ...

  6. 学习笔记之html5相关内容

    写一下昨天学习的html5的相关内容,首先谈下初次接触html5的感受.以前总是听说html5是如何的强大,如何的将要改变世界.总是充满了神秘感.首先来谈一下我接触的第一个属性是  input的里面的 ...

  7. 基于KNN的相关内容推荐

    如果做网站的内容运营,相关内容推荐可以帮助用户更快地寻找和发现感兴趣的信息,从而提升网站内容浏览的流畅性,进而提升网站的价值转化.相关内容 推荐最常见的两块就是“关联推荐”和“相关内容推荐”,关联推荐 ...

  8. 第一天上午——HTML网页基础知识以及相关内容

    今天上午学习了HTML基础知识以及相关内容,还有DW的基本使用方法. HTML(HyperText Markup Language):超文本标记语言,超文本:网页中除了包含文本文字之外,还包含了图片, ...

  9. python爬虫主要就是五个模块:爬虫启动入口模块,URL管理器存放已经爬虫的URL和待爬虫URL列表,html下载器,html解析器,html输出器 同时可以掌握到urllib2的使用、bs4(BeautifulSoup)页面解析器、re正则表达式、urlparse、python基础知识回顾(set集合操作)等相关内容。

    本次python爬虫百步百科,里面详细分析了爬虫的步骤,对每一步代码都有详细的注释说明,可通过本案例掌握python爬虫的特点: 1.爬虫调度入口(crawler_main.py) # coding: ...

随机推荐

  1. 安卓控件 仪表盘控件 柱状图控件 曲线控件 xamarin.android 分类器 瓶子控件 报警控件 水箱控件 进度条控件等

    本篇博客主要介绍一个控件库,HslControls.dll 的界面,这个控件库支持winform,winform的参考另一篇文章:https://www.cnblogs.com/dathlin/p/1 ...

  2. Spring Cloud Gateway的动态路由怎样做?集成Nacos实现很简单

    一.说明 网关的核心概念就是路由配置和路由规则,而作为所有请求流量的入口,在实际生产环境中为了保证高可靠和高可用,是尽量要避免重启的,所以实现动态路由是非常有必要的:本文主要介绍 Spring Clo ...

  3. drf框架中jwt认证,以及自定义jwt认证

    0909自我总结 drf框架中jwt 一.模块的安装 官方:http://getblimp.github.io/django-rest-framework-jwt/ 他是个第三方的开源项目 安装:pi ...

  4. SpringBoot系列教程web篇之过滤器Filter使用指南扩展篇

    前面一篇博文介绍了在 SpringBoot 中使用 Filter 的两种使用方式,这里介绍另外一种直接将 Filter 当做 Spring 的 Bean 来使用的方式,并且在这种使用方式下,Filte ...

  5. ‎Cocos2d-x 学习笔记(15.1) EventDispatcher

    EventDispatcher对监听器进行管理,围绕着监听器工作.可以添加.删除.暂停/恢复监听器.分发事件到监听器. 1. 一些成员 /** 把ListenerID和同ID监听器的容器对应 */ s ...

  6. 剑指Offer(十九)——顺时针打印矩阵

    题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字. 例如,如果输入如下4 X 4矩阵: 1   2    3     4 5   6    7     8 9   10  11  ...

  7. Python编程系列---使用装饰器传参+字典实现动态路由

    # 实现一个空路由表,利用装饰器将url和功能函数的对应关系自动存到这个字典中 router_dict = {} # 定义一个装饰器 # 再给一层函数定义,用来传入一个参数,这个参数就是访问的页面地址 ...

  8. 5分钟彻底理解Redis持久化

    Redis持久化 RDB快照 在默认情况下,Redis将内存数据库快照保存到dump.rdb的二进制文件中. 可以对Redis进行设置,让它在"N秒内数据集至少有N个改动", 这一 ...

  9. Mysql高手系列 - 第27篇:mysql如何确保数据不丢失的?我们借鉴这种设计思想实现热点账户高并发设计及跨库转账问题

    Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 欢迎大家加我微信itsoku一起交流java.算法.数据库相关技术. 这是Mysql系列第27篇. 本篇文章我们先来 ...

  10. ES6基本语法入门

    一.用let代替var声明变量 ES5中,我们可以在代码中任意位置声明变量,甚至可以重写已经声明的变量,ES6引入了一个let关键字,它是新的var. let language = 'javascri ...