02-java内存模型:解决并发编程的可见性、有序性问题

并发编程的两个问题:缓存导致的不可见,编译优化导致的有序性问题

解决:禁用缓存,禁用编译优化。但是总不能所有程序都禁用吧,这样程序的性能就堪忧了。

Java内存模型:按需禁用缓存,禁用编译优化。

从本质上来讲,Java内存模型规范了JVM如何提供按需禁用缓存和编译优化的方法。具体来说,这些方法包括volatile、synchronized、和final三个关键字,以及七项happens-before规则。

一、volatile

  它修饰的变量,告诉编译器,对这个变量的读写,不能使用cpu缓存,必须从内存中读取或写入。

二、synchronized

  管程,在Java中指的就是synchronized。在进入代码块之前,会自动加锁,在代码块执行完会自动释放锁。

三、final

  它修饰的变量,告诉编译器:这个变量生而不变,可以可劲儿优化。

 

happens-before规则:

1、程序的顺序性规则

指在一个线程中,按照程序顺序,前面的操作happens-before于后续的任意操作

2、volatile变量规则

指 对一个volatile变量的写操作,happens-before于后续对这个volatile变量的读操作。

3、传递性

如果A  happens-before于B,B happens-before于 C,那么A happens-before 于 C。

4、管程中锁的规则

即synchronized代码块happens-before于后续进入该代码块以及后续的所有操作。

5、线程start()规则

线程A启动子线程B,那么子线程B能够看到线程A在启动线程B前的操作。

6、线程join()规则

这条是关于线程等待的。在线程A中调用线程B的join()并成功返回,那么线程B中的任意操作happens-before于该join()操作的返回。

7、线程终止规则

(1).线程终止规则:线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。
(2).线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中断发生。

 

四、Java内存模型底层怎么实现的?

主要是通过内存屏障(memory barrier)禁止重排序的,即时编译器根据具体的底层体系架构,将这些内存屏障替换成具体的 CPU 指令。对于编译器而言,内存屏障将限制它所能做的重排序优化。而对于处理器而言,内存屏障将会导致缓存的刷新操作。比如,对于volatile,编译器将在volatile字段的读写操作前后各插入一些内存屏障。

posted @ 2019-10-11 23:13  45°仰望星空  阅读(226)  评论(0编辑  收藏  举报