java 并发——volatile
java 并发——volatile
介绍
维基百科: volatile 是一个类型修饰符(type specifier).volatile 的作用是确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
看了上面的话感觉不是那么的好理解,因为 volatile 关键字是和 java 内存模型 JMM(java memory model)是息息相关的,所以在介绍 volatile 之前我们先来看一下 java 内存模型.
内存模型概念
我们的程序执行指令是从 cpu 中执行的,程序执行肯定和数据脱不开干系,这些数据肯定都是在计算机的物理内存中进行.但是随着 cpu 越来越牛x,而内存的话就会显得相对来说不那么效率,这就导致每次 cpu 执行导致每次操作数据都要去内存操作,这样就很耗费时间.
由于计算机的存储设备与 cpu 的运算速度有几个数量级的差距,所以现代计算机系统都不得不加入一层读写速度尽可能接近处理器运算速度的高速缓存(Cache)来作为内存与处理器之间的缓冲:将运算需要使用到的数据复制到缓存中,让运算能快速进行,当运算结束后再从缓存同步回内存之中,这样处理器就无须等待缓慢的内存读写了。
解决了效率的问题但是随之而来也就出现了新的问题需要解决——缓存一致性.因为在程序运行期间会将运行所需要的数据从内存中复制一份到 cpu 高速缓存中之后再进行对应的运算,再运算期间数据的读取是从高速缓存直接读取并不会再取读取内存中的数据了,只有再运算结果出来后才会将数据重新刷新会到内存中.
解决方法:
- 通过数据总线加锁的方式 LOCK.(但是这样效率极为低下不建议)
- 缓存一致性协议.(确保每个缓存中使用的共享变量的副本是一致的。其核心思想如下:当某个 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。这种现象就是缓存一致性问题。
我们在并发编程中都会知道这几个概念:
- 原子性: 即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行.
- 可见性: 可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值.
- 有序性: 即程序执行的顺序按照代码的先后顺序执行.多线程环境下有影响.
volatile
我们在回顾一下一开始介绍 volatile 的话: volatile 是一个类型修饰符(type specifier).volatile 的作用是确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
看了上面的话只表达出了一点: 可见性.其实还有一个作用就是禁止指令重排序(重排序后面会单独说).所以使用 volatile 关键字来修饰变量就不会存在缓存一致性的问题了.现在我们简单说下 volatile 是怎么禁止指令重排序的: 加入 volatile关键字和没有加入 volatile 关键字时所生成的汇编代码发现,加入 volatile 关键字时,会多出一个 lock 前缀指令。lock 前缀指令其实就相当于一个内存屏障。内存屏障是一组处理指令,用来实现对内存操作的顺序限制。
volatile 就暂且到这里了,感兴趣的朋友可以继续深入研究.volatile 相对于 synchronized 稍微轻量些,在某些场合它可以替代 synchronized,但是又不能完全取代 synchronized.感谢观看!
java 并发——volatile的更多相关文章
- Java并发-volatile的原理及用法
Java并发-volatile的原理及用法 volatile属性:可见性.保证有序性.不保证原子性.一.volatile可见性 在Java的内存中所有的变量都存在主内存中,每个线程有单独CPU缓存内存 ...
- Java并发——volatile的原理
111 Java并发——volatile的原理
- Java 并发 —— volatile 关键字
volatile 修饰变量等于向编译器传达如下两层含义: 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的. 禁止进行指令重排序. volat ...
- JAVA并发--volatile
学过计算机组成原理的一定知道,为了解决内存速度跟不上CPU速度这个问题,在CPU的设计中加入了缓存机制,缓存的速度介于CPU和主存之间.在进行运算的时候,CPU将需要的数据映射一份在缓存中,然后直接操 ...
- Java并发--volatile关键字
一.volatile的实现原理 synchronized是阻塞式同步,在线程竞争激烈的情况下会升级为重量级锁,而volatile就可以说是JVM提供的最轻量级的同步机制.JMM告诉我们,各个线程会将共 ...
- Java并发--volatile详情
volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ...
- Java并发——volatile关键字
什么是内存可见性? 这里就要提一下JMM(Java内存模型).当线程在运行的时候,并不是直接直接修改电脑主内存中的变量的值.线程间通讯也不是直接把一个线程的变量的值传给另一个线程,让其刷新变量.下面是 ...
- Java并发——volatile关键字的使用
volatile关键字的使用volatile关键字原理适合使用volatile关键字的情况当且仅当满足以下所有条件时,才==应该==使用volatile关键字:volatile关键字的作用volati ...
- Java并发——volatile
CPU的内存模型如下:
随机推荐
- Visual Studio Code 键盘参考表
2019年4月6日,对照中英翻译. 一般 Ctrl+Shift+P, F1 显示命令调色板 Ctrl+P 快速打开,转到文件… Ctrl+Shift+N 新建窗口/实例 Ctrl+Shift+W ...
- 蓝桥杯:排它平方数-java
问题描述: 小明正看着 203879 这个数字发呆.原来,203879 * 203879 = 41566646641这有什么神奇呢?仔细观察,203879 是个6位数,并且它的每个数位上的数字都是不同 ...
- Spring clound 微服务--理解篇
定义:微服务就是一些协调工作的小而自治的服务 优点: 异构性:不同微服务可以使用不同的语言实现, 后端数据库也可以根据自身业务定义服务. 弹性: 一个组件不可用,不会导致级联故障.一个系统出了问题,不 ...
- C#的扩展方法学习
一,什么是扩展方法? 1,扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 2,扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用 ...
- Educational Codeforces Round 33 D. Credit Card
Credit Card time limit per test2 seconds memory limit per test256 megabytes Recenlty Luba got a cred ...
- etcd注册服务
etcd作为最简单(轻量,精简)的kv服务.etcd可以应用很多方面,但是它有一个特点,etcd只是基础,需要你自己实现功能.它不像其其它组件开箱即用,也正是如此,它足够简单精巧. 回到主题,etcd ...
- SQL数据库—<7>事务、异常和游标
事务 一.什么是事务能够保证数据的一致性的代码控制,要么执行提交,要么滚回事务的初始状态 二.事务的四大特性:ACIDA:原子性-------事务不可拆开,要么执行要么回滚无中间状态C:一致性---- ...
- 关于uboot一些概念
U-boot的环境变量值得注意的有两个: bootcmd 和bootargs. bootcmd 前面有说过bootcmd是自动启动时默认执行的一些命令,因此你可以在当前环境中定义各种不同配置,不同环境 ...
- 命令分析nginx访问日志的用法
awk分析日志常用高级使用命令方法 分析访问日志(Nginx为例) 日志格式: '$remote_addr - $remote_user [$time_local] "$request&qu ...
- Codeforces 1179D 树形DP 斜率优化
题意:给你一颗树,你可以在树上添加一条边,问添加一条边之后的简单路径最多有多少条?简单路径是指路径中的点只没有重复. 思路:添加一条边之后,树变成了基环树.容易发现,以基环上的点为根的子树的点中的简单 ...