java 并发——volatile


介绍

维基百科: volatile 是一个类型修饰符(type specifier).volatile 的作用是确保本条指令不会因编译器的优化而省略,且要求每次直接读值。

看了上面的话感觉不是那么的好理解,因为 volatile 关键字是和 java 内存模型 JMM(java memory model)是息息相关的,所以在介绍 volatile 之前我们先来看一下 java 内存模型.

内存模型概念

我们的程序执行指令是从 cpu 中执行的,程序执行肯定和数据脱不开干系,这些数据肯定都是在计算机的物理内存中进行.但是随着 cpu 越来越牛x,而内存的话就会显得相对来说不那么效率,这就导致每次 cpu 执行导致每次操作数据都要去内存操作,这样就很耗费时间.

由于计算机的存储设备与 cpu 的运算速度有几个数量级的差距,所以现代计算机系统都不得不加入一层读写速度尽可能接近处理器运算速度的高速缓存(Cache)来作为内存与处理器之间的缓冲:将运算需要使用到的数据复制到缓存中,让运算能快速进行,当运算结束后再从缓存同步回内存之中,这样处理器就无须等待缓慢的内存读写了。

解决了效率的问题但是随之而来也就出现了新的问题需要解决——缓存一致性.因为在程序运行期间会将运行所需要的数据从内存中复制一份到 cpu 高速缓存中之后再进行对应的运算,再运算期间数据的读取是从高速缓存直接读取并不会再取读取内存中的数据了,只有再运算结果出来后才会将数据重新刷新会到内存中.

解决方法:

  1. 通过数据总线加锁的方式 LOCK.(但是这样效率极为低下不建议)
  2. 缓存一致性协议.(确保每个缓存中使用的共享变量的副本是一致的。其核心思想如下:当某个 cpu 在写数据时,如果发现操作的变量是共享变量,则会通知其他 cpu 告知该变量的缓存行是无效的,因此其他 cpu 在读取该变量时,发现其无效会重新从主存中加载数据。)

java 内存模型

java 内存模型规定了所有的变量都存储在主内存中,每条运行的线程还是各自的工作内存区域,线程运行的是会从主内存中将变量从主内存拷贝一份到自己的工作内存,线程对变量的所有操作都必须在工作内存中进行,而不是直接操作主内存,不同的线程之间工作内线是不会共享的。直到线程运算结束将值刷新到主内存后,其他线程才可见(可见性).

先举一个场景

public class Test {
static int i = 1; public static void main(String[] args) {
Thread t1 = new Thread(() -> {
i++;
});
Thread t2 = new Thread(() -> {
i++;
});
t1.start();
t2.start();
System.out.println(Test.i);
}
}

这个场景输出有可能不是 3,两个线程从主存中读取 i 的值(1)到各自的高速缓存中,然后线程 t1 执行 +1 操作并将结果写入高速缓存中,最后写入主存中,此时主存 i==2,线程 t2 做同样的操作,但是线程 t2 的工作内存 i 的值有可能还是 1但是现在主存中的 i 应该是 2。所以 t2 执行完最终结果为 2 再将 2 刷新入主内存中而并不是 3。这种现象就是缓存一致性问题。

我们在并发编程中都会知道这几个概念:

  1. 原子性: 即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行.
  2. 可见性: 可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值.
  3. 有序性: 即程序执行的顺序按照代码的先后顺序执行.多线程环境下有影响.

volatile

我们在回顾一下一开始介绍 volatile 的话: volatile 是一个类型修饰符(type specifier).volatile 的作用是确保本条指令不会因编译器的优化而省略,且要求每次直接读值。

看了上面的话只表达出了一点: 可见性.其实还有一个作用就是禁止指令重排序(重排序后面会单独说).所以使用 volatile 关键字来修饰变量就不会存在缓存一致性的问题了.现在我们简单说下 volatile 是怎么禁止指令重排序的: 加入 volatile关键字和没有加入 volatile 关键字时所生成的汇编代码发现,加入 volatile 关键字时,会多出一个 lock 前缀指令。lock 前缀指令其实就相当于一个内存屏障。内存屏障是一组处理指令,用来实现对内存操作的顺序限制。

volatile 就暂且到这里了,感兴趣的朋友可以继续深入研究.volatile 相对于 synchronized 稍微轻量些,在某些场合它可以替代 synchronized,但是又不能完全取代 synchronized.感谢观看!

java 并发——volatile的更多相关文章

  1. Java并发-volatile的原理及用法

    Java并发-volatile的原理及用法 volatile属性:可见性.保证有序性.不保证原子性.一.volatile可见性 在Java的内存中所有的变量都存在主内存中,每个线程有单独CPU缓存内存 ...

  2. Java并发——volatile的原理

    111 Java并发——volatile的原理

  3. Java 并发 —— volatile 关键字

    volatile 修饰变量等于向编译器传达如下两层含义: 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的. 禁止进行指令重排序. volat ...

  4. JAVA并发--volatile

    学过计算机组成原理的一定知道,为了解决内存速度跟不上CPU速度这个问题,在CPU的设计中加入了缓存机制,缓存的速度介于CPU和主存之间.在进行运算的时候,CPU将需要的数据映射一份在缓存中,然后直接操 ...

  5. Java并发--volatile关键字

    一.volatile的实现原理 synchronized是阻塞式同步,在线程竞争激烈的情况下会升级为重量级锁,而volatile就可以说是JVM提供的最轻量级的同步机制.JMM告诉我们,各个线程会将共 ...

  6. Java并发--volatile详情

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

  7. Java并发——volatile关键字

    什么是内存可见性? 这里就要提一下JMM(Java内存模型).当线程在运行的时候,并不是直接直接修改电脑主内存中的变量的值.线程间通讯也不是直接把一个线程的变量的值传给另一个线程,让其刷新变量.下面是 ...

  8. Java并发——volatile关键字的使用

    volatile关键字的使用volatile关键字原理适合使用volatile关键字的情况当且仅当满足以下所有条件时,才==应该==使用volatile关键字:volatile关键字的作用volati ...

  9. Java并发——volatile

    CPU的内存模型如下:

随机推荐

  1. 如何在列表,字典,集合中,根据条件筛选数据 -- Python数据结构与算法相关问题与解决技巧

    实际案例: 1.过滤掉列表 [3,9,-1,10,20,-2..]的负数 2.筛出字典{'LiLei':79,'Jim':88,'Lucy':92...}中值高于90的项 3.筛出集合 {77,89, ...

  2. python 装饰器 对类和函数的装饰

    #装饰器:对类或者函数进行功能的扩展  很多需要缩进的没有进行缩进'''#第一步:基本函数def laxi(): print('拉屎')#调用函数laxi()laxi() print('======= ...

  3. 利用Graphziv帮助理解复杂的类层次关系

    最近在学习osg三维视景仿真平台,学习的过程中涉及到许多的类与类之间的继承和包含关系.在复杂点的例子中,许多的类和节点组合在一起,很容易让人迷失方向.在编译源代码的时候,无意间发现了Graphviz这 ...

  4. 常用缓存淘汰算法(LFU、LRU、ARC、FIFO、MRU)

    缓存算法是指令的一个明细表,用于决定缓存系统中哪些数据应该被删去. 常见类型包括LFU.LRU.ARC.FIFO.MRU. 最不经常使用算法(LFU): 这个缓存算法使用一个计数器来记录条目被访问的频 ...

  5. Spring IOC DI AOP 的简单理解及应用

    Spring两大特性:IOC 和AOP.IOC 控制反转,AOP 面向切面编程 spring 核心容器的主要组件时Bean工厂(BeanFactory) ,Bean 工厂使用控制反转模式来降低程序代码 ...

  6. 网站设置成代理后,chrome chrome HTTP ERROR 502

    在阿里云上设置CNAME代理后,发现www.xxxx.com出现502,但是http://xxxx.com却可以访问. ping了一下都可以,网上搜了搜原来和nginx.conf配置有关 配置如下,上 ...

  7. jq实现两个input输入同时不为空时,改变确认框背景颜色

    <!DOCTYPE html> <html> <head> <title></title> </head> <body&g ...

  8. Docker镜像仓库的搭建--> Harbor篇

    简介 Harbor是VMware公司开源的一个企业级Docker Registry项目,项目地址:https://github.com/goharbor/harbor Harbor作为一个企业级私有R ...

  9. MVC:页面提交JQ动态生成的输入框的值得解决方案:

    一,动态生成JS写法 <script type="text/javascript"> , , , ); function Additional() { var num ...

  10. 【学习总结】Python-3-逻辑运算符

    参考:菜鸟教程-Python3运算符 逻辑运算符的计算规则划重点: 并不是只返回布尔型,有时会返回变量的数值 (优先级:not>and>or) 总结: '与或非'三件套中,not与数学逻辑 ...