Volatile 原理及使用,java并发中的可见性问题
1.解决并发编程中的可见性问题
volatile 代表不使用cpu缓存,修改后的数据,将直接刷到内存中,被volatile修饰的变量,读取的时候,也是从内存中读取,不从cpu缓存中读取
上代码
// 以下代码来源于【参考1】
class VolatileExample {
int x = 0;
volatile boolean v = false;
public void writer() {
x = 42;
v = true;
}
public void reader() {
if (v == true) {
// 这里x会是多少呢?
}
}
}
例如上面的示例代码,
假设线程 A 执行 writer() 方法,按照 volatile 语义,会把变量 “v=true” 写入内存;
假设线程 B 执行 reader() 方法,同样按照 volatile 语义,线程 B 会从内存中读取变量 v,如果线程 B 看到 “v == true” 时,那么线程 B 看到的变量 x 是多少呢?
直觉上看,应该是 42,那实际应该是多少呢?这个要看 Java 的版本,如果在低于 1.5 版本上运行,x 可能是 42,也有可能是 0;如果在 1.5 以上的版本上运行,x 就是等于 42。
为什么呢?
- 变量 x 可能被 CPU 缓存而导致可见性问题。这个问题在 1.5 版本已经被圆满解决了。Java 内存模型在 1.5 版本对 volatile 语义进行了增强。怎么增强的呢?答案是一项 Happens-Before 规则。
这个规则就是:
前面一个操作的结果对后续操作是可见的
2.六项Happens-Before规则
1. 程序的顺序性规则
这条规则是指在一个线程中,按照程序顺序,前面的操作 Happens-Before 于后续的任意操作。这还是比较容易理解的,比如刚才那段示例代码,按照程序的顺序,第 6 行代码 “x = 42;” Happens-Before 于第 7 行代码 “v = true;”,这就是规则 1 的内容,也比较符合单线程里面的思维:程序前面对某个变量的修改一定是对后续操作可见的。
2. volatile 变量规则
对一个 volatile 变量的写操作, Happens-Before 于后续对这个 volatile 变量的读操作。
3.传递性
这条规则是指如果 A Happens-Before B,且 B Happens-Before C,那么 A Happens-Before C。
对应到上面的源码中就是
x=42 Happens-Before 写变量v=true 对应规则(程序的顺序性规则)
写变量v=true Happens-Before 读变量if(v==true) 对应规则2(volatile变量规则)
4.管程中的锁规则
管程,就是同步愿语,java中指的就是synchronized
上代码
synchronized (this) { //此处自动加锁
// x是共享变量,初始值=10
if (this.x < 12) {
this.x = 12;
}
} //此处自动解锁
假设 x 的初始值是 10,线程 A 执行完代码块后 x 的值会变成 12(执行完自动释放锁),线程 B 进入代码块时,能够看到线程 A 对 x 的写操作,也就是线程 B 能够看到 x==12
5.start()规则
主线程 A 启动子线程 B 后,子线程 B 能够看到主线程在启动子线程 B 前的操作。
上代码
Thread B = new Thread(()->{
// 主线程调用B.start()之前
// 所有对共享变量的修改,此处皆可见
// 此例中,var==77
});
// 此处对共享变量var修改
var = 77;
// 主线程启动子线程
B.start();
6.join()规则
如果在线程 A 中,调用线程 B 的 join() 并成功返回,那么线程 B 中的任意操作 Happens-Before 于该 join() 操作的返回
3.Java 内存模型
Java 内存模型规范了 JVM 如何提供按需禁用缓存和编译优化的方法
具体来说,这些方法包括 volatile、synchronized 和 final 三个关键字,以及六项 Happens-Before 规则
Volatile 原理及使用,java并发中的可见性问题的更多相关文章
- 深入浅出Java并发中的CountDownLatch
1. CountDownLatch 正如每个Java文档所描述的那样,CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行.在Java并发中 ...
- java并发中CountDownLatch的使用
文章目录 主线程等待子线程全都结束之后再开始运行 等待所有线程都准备好再一起执行 停止CountdownLatch的await java并发中CountDownLatch的使用 在java并发中,控制 ...
- java并发中ExecutorService的使用
文章目录 创建ExecutorService 为ExecutorService分配Tasks 关闭ExecutorService Future ScheduledExecutorService Exe ...
- java并发中的Synchronized关键词
文章目录 为什么要同步 Synchronized关键词 Synchronized Instance Methods Synchronized Static Methods Synchronized B ...
- Java并发编程-线程可见性&线程封闭&指令重排序
一.指令重排序 例子如下: public class Visibility1 { public static boolean ready; public static int number; } pu ...
- 一起来看看java并发中volatile关键字的神奇之处
并发编程中的三个概念: 1.原子性 在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行. 2.可见性 对于可见性,Java提供了volati ...
- Java并发中的CopyOnWrite容器
Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...
- Generate PDF in Sourcing through concurrent request,在EBS java并发中调用指定am的方法
package oracle.apps.pon.printing.cp; import java.io.InputStream; import java.io.FileOutputStream; im ...
- java并发中的锁
java中的锁,最基本的是Lock接口. Lock接口中的方法,主要是: lock(): 获取锁,lock()方法会对Lock实例对象进行加锁,因此所有对该对象调用lock()方法的线程都会被阻塞,直 ...
随机推荐
- springboot的logback的配置文件
之前敲出来一个 logback 的配置文件,防止以后找起来麻烦在这里存个档 修改了日志输出的内容 设置默认级别为 INFO 正常日志 ( TRACE 到 WARN ) 输出到单独的文件夹 异常日志 ( ...
- ASP微信服务号H5客户登陆,且获取客户授权的用户基本信息
ASP微信服务号H5客户登陆,且获取客户授权的用户基本信息是需要客户授权,下面讲解详细步骤: 第一步:客户点击登录页,自动跳转到微信服务器端获取code 第二步:用第一步获取的code去获取客户的ac ...
- 从苏宁电器到卡巴斯基第29篇:难忘的三年硕士时光 VII
我们可能无家可归 那天晚上和导师道别后,我们几个还聚在一起开了一个小会.当时大家觉得最坏的情况就是学院不肯让步,不能满足我们导师提出的条件.那么这样的话,我们几个只能够重新找导师了.而我们数媒专业里面 ...
- (CV学习笔记)Attention
Attention(注意力机制) Attention for Image Attention for Machine Translation Self-Attention 没有image-Attent ...
- 【转】docker打包python应用
转自https://www.cnblogs.com/shenh/p/9518343.html 一.前言 容器使用沙箱机制,互相隔离,优势在于让各个部署在容器的里的应用互不影响,独立运行,提供更高的安全 ...
- InnoDB解决幻读的方案——LBCC&MVCC
最近要在公司内做一次技术分享,思来想去不知道该分享些什么,最后在朋友的提示下,准备分享一下MySQL的InnoDB引擎下的事务幻读问题与解决方案--LBCC&MVCC.经过好几天的熬夜通宵,终 ...
- MySQL5.7升级到8.0过程详解
前言: 不知不觉,MySQL8.0已经发布好多个GA小版本了.目前互联网上也有很多关于MySQL8.0的内容了,MySQL8.0版本基本已到稳定期,相信很多小伙伴已经在接触8.0了.本篇文章主要介绍从 ...
- 2020 ICPC EC Final西安现场赛游记
也不知道从何说起,也不知道会说些什么,最想表达的就是很累很累. 从第一天去的时候满怀希望,没什么感觉甚至还有一些兴奋.到后来一直在赶路,感觉很疲惫,热身赛的时候觉得马马虎虎,导致热身赛被咕.然后教练就 ...
- linux远程下载文件 的两种方法之 ftp命令和scp命令
ftp命令: 服务器有安装ftp Server,另外一台linux可以使用ftp的client程序来进行文件的拷贝读取和下载. 1. 连接ftp服务器 格式:ftp [hostname| ip-ad ...
- [Python] 命名空间&作用域
Python的类语句不会创建实例 类会创建命名空间,通过对象访问类的属性和方法 类不会创建作用域,对方法和属性的引用必须加以限定(如在方法中必须通过self引用实例的属性) class My1(): ...