Java内存模型 vs JVM运行时数据区:
多线程中的问题:
CPU指令重排序:
Java编程语言的语言语义允许Java编译器和微处理器进行执行优化,这些优化导致了与其交互的代码不在同步,从而导致看似矛盾的行为。
CPU与Java编译器(JIT编译)会指令重排。
JIT编译器(Just In Time Compiler):
脚本语言与编译语言的区别?
解释执行:即在执行时,有语言的解释器将其一条条翻译成机器可识别的指令。
编译执行:将程序直接编译成机器可以识别的指令码(批量编译)
Java是脚本语言还是编译语言?(Java语言是介于解释执行与编译执行之间)
JIT编译器的指令重排
volatile关键字:
可见性问题:让一个线程对共享变量的修改,能够及时的被其他线程看到。
Java内存模型规定:
对volatile变量v的写入,与所有其他线程后续对v的读同步。
要满足这些条件,所有volatile关键字就有这些功能:
1.禁止缓存:
volatile变量的访问控制符会加个ACC_VOLATILE
2.对volatile变量相关的指令不做重排序。
代码:
volatile boolean isRunning = true;
javap:
volatile boolean isRunning;
descriptor: Z
flags: ACC_VOLATILE
参考:Java虚拟机规范
Shared Variables定义:
可以在线程之间共享的内存称为共享内存或者堆内存。
所有实例字段、静态字段和数组元素都存储在堆内存中,这些字段和数据都是标题中提到的共享变量。
冲突:如果至少有一个访问是写操作,那么对同一个变量的两次访问是冲突。
这些能被多个线程访问的共享变量是内存模型规范的对象。
线程间操作的定义:
对于同步的规则定义:
1.对volatile变量v的写入,与所有其他线程后续对v的读同步。
2.对于监视器m的解锁与所有后续操作对于m的加锁同步。
3.对于每个属性写入的默认值(0、false、null)与每个线程对其进行的操作同步。
4.启动线程的操作与线程中id第一个操作同步。
5.线程T2的最后操作与线程T1发现线程T2已经结束同步。(isAlive,join)
Happens-before先行发生原则:
final在JMM中的处理:
final在该对象的构造函数中设置对象的字段,当线程看到该对象时,将始终看到该对象的final字段的正确构造版本。
伪代码实例:
f = new finalDemo();
读取到的f.x一定是最新,x为final字段。
如果在构造函数中设置字段后发生读取,则会看到该final字段分配的值,否则它将看到默认值。
Word Tearing字节处理: