Java内存模型是一个规范,为了解决并发模式下的可见性、原子性和顺序性问题。Java内存模型规范了JVM如何提供按需禁用缓存和编译优化的方法。具体来说,这些方法包括volatile、synchronized、final三个关键字,以及6项Happens-Before规则。
volatile
原语是禁用CPU缓存,即必须从内存中读取和写入变量。禁用缓存不是Java语言特有的,在C语言中也有这个概念。
在Java中,volatile除了代表禁用CPU缓存,还表示禁止重排???FIXME
Hapens Before规则
前面一个操作的结果对后续操作是可见的。Happens-Before约束了编译器的优化行为。6项Happens-Before规则都是针对可见性的。
1. 程序的顺序性规则
2. volatile规则
3. 传递性规则
4. 管程中锁的规则
5. 线程start规则
6. 线程join规则
顺序性规则,符合单线程里面的思维,程序前面对某个变量的修改一定是对后续操作可见的。
传递性规则,如果A Happens-Before B,并且B Happens-Before C,则A Happens-Before C。
管程中锁的规则,对一个锁的解锁Happens-Before于后续对这个锁的加锁。
不是应该先加锁再解锁吗?
管程,同步的原语,在Java中,代指synchronized。
互斥锁,解决原子性问题。原子性问题的产生原因是由于线程切换(语言级的一个操作未执行完,其他线程被CPU调度开始执行,也用到了一个对前一个线程来说未完成的变量操作结果)。
把一段需要互斥执行的逻辑成为“临界区”
锁的优化
- 细化粒度
细化粒度可能会带来死锁问题,
死锁定义:一组互相竞争资源的线程因互相等待,导致永久阻塞的现象。
死锁出现的四个条件:
- 互斥,共享资源X和Y只能被同一个线程占有;
- 占有且等待,线程T1已经取得共享资源X,在等待共享资源Y的时候,不释放共享资源X;
- 不可抢占,其他线程不能抢占线程T1占有的资源;
- 循环等待,线程T1等待线程T2占有的资源,线程T2等待线程T1占有的资源。
在实现中,只要破坏上面四个条件中的任意一个就可避免死锁现象。
网友评论