1. Java并发编程-Java内存模型

并发问题的原因可以归结为三大类:可见性,有序性和原子性。

可见性的原因是CPU缓存,不同CPU之间缓存的数据互相之间不可见。
有序性的原因是编译优化(指令重排序)
原子性的原因是一条高级指令可能对应多个CPU指令,而OS只能保证CPU指令的原子性。

解决方案

解决可见性和有序性可以通过禁用CPU缓存和禁用编译优化实现,但这样会严重影响程序性能,合理的方案应该是按需禁用。Java内存模型规范了JVM如何提供按需禁用缓存和编译优化的方法,具体包括:volatile, synchronized和final关键字以及六项Happens-Before规则

volatile

这个关键字不是Java语言特有的,C语言中就已引入,最原始的意义就是禁用CPU缓存。如声明一个变量 volatile int a = 1; 表示告诉编译器,对这个变量的读写禁用CPU缓存,必须从内存读写。

Happens-Before规则

它的含义是:前面一个操作的结果对后续操作是可见的。Happens-Before规则约束了编译器的优化行为,虽允许编译优化,但要求编译器优化后一定遵守Happens-Before规则。

1. 程序的顺序性规则

这条规则指:同一个线程中,按照程序顺序,前面的操作happens-Before于后续的任意操作。比较容易理解,即程序前面对某个变量的修改一定是对后续操作可见的。

2. Volatile

对一个 volatile 变量的写操作相对于后续对这个 volatile 变量的读操作可见。即volatile变量直接从内存读写

3. 传递性

指如果 A Happens-Before B,且 B Happens-Before C,那么 A Happens-Before C。

4. 管程中锁的规则

指对一个锁的解锁happens-before于后续对这个锁的加锁。管程是一种通用的同步原语,在Java中就是synchronized。管程中的锁在Java中是隐式实现的,由编译器自动完成加解锁。

即一个线程在同步代码块中对变量的写对另一个进入代码块的线程可见。

5. 线程start()规则

指主线程A启动子线程B后,子线程B能够看到主线程在启动B之前的操作。

6. 线程join规则

指主线程A等待子线程B完成(主线程A中调用B线程的join()方法实现),当B完成后,主线程能够看到子线程的操作(共享变量的值可见)。

final关键字

在JDK 1.5 以后 Java 内存模型对 final 类型变量的重排进行了约束。现在只要我们提供正确构造函数没有“逸出”,就不会出问题。

小结

Java的内存模型是并发编程领域的一次重要创新,其中happens-before规则比较难懂一些。Happens-before本质是上解决可见性的问题。如果A happens-before B, 即使A在线程1中发生,那么在线程2中也能看到A发生的事情。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值