Java中内存模型的原理是什么,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。 1. JMM简要知识 语义规范
Java编程语言的语义允许编译器和微处理器执行优化,从而与不正确同步的代码进行交互来完成工作. 线程内语义是单线程程序的语义,它允许根据线程内读操作看到的值来完全预测线程的行为;由于单线程内的实现是在其上下文执行的, 可以通过评估线程的实现从而确定执行中的线程的操作是否合法. 程序遵循线程内语义: 在线程隔离状态下,每个线程的操作必须由该线程的语义控制,但是每个读操作看到的值由内存模型决定.
JMM规范
从数据存储上,对于共享数据的读写操作,JMM会通过线程工作内存以及JVM的堆内存来对数据进行读写操作(类比互联网业务,工作内存类比为redis等缓存,堆内存类比为数据储存载体,如数据库) 从代码优化上,JMM为了提升性能,会针对程序顺序代码进行重排序甚至删除不必要的同步代码
JMM概要
给定程序以及一个检测程序是否合法的执行跟踪,JMM工作原理是检查执行跟踪中的每个读,并根据某些规则检查读观察到的写是否有效 主要保证执行的每个结果与内存模型预期值一致,那么它可以不关心实现者是如何实现程序的行为 内存模型决定在程序的每个点可以读取哪些值。在隔离状态下,每个线程的操作必须由该线程的语义控制,但是每个读操作看到的值由内存模型决定 每次在线程内对变量进行写行为产生一个线程间的动作时,它必须匹配程序顺序中紧随其后的读行为的线程间动作,其中对于线程的读操作行为获取的值是由于JMM决定的值
2. JMM与顺序一致性模型 程序顺序与顺序一致性
程序顺序 可描述为线程间所有动作是根据线程内语义执行操作顺序的一个集合 简言之,就是在线程内的操作所见即所得,即程序代码顺序
顺序一致性内存模型 顺序一致性问题
JMM在顺序一致性方面的努力
// shared.java int pwrite = 0; int cwrite = 0; // producer.java int pread = 0; int r1 = 0; run(){ r1 = 20; // --- 1 pread = cwrite; // --- 2 pwrite = 10; // --- 3 } // consumer.java int cread = 0; int r2 = 0; run(){ cread = pwrite; // --- 4 r2 = 21; // --- 5 cwrite = 20; // --- 6 }
代码分析 基于JMM模型: 由于存在数据竞争,上面的代码执行顺序会在编译器阶段,JMM允许对程序代码进行重排序,输出结果会出现pread = cwrite = 20 与 cread = pwrite = 10的情况 基于一致性内存模型: 将会正常输出,不会出现pread = cwrite = 20 与 cread = pwrite = 10的情况,但是线程之间的顺序会交替执行
加锁方案 小结 在存在数据竞争的条件下,JMM无法保证线程之间的执行顺序,而顺序一致性保证与代码执行的顺序相同,即使线程的执行顺序存在交替执行也不影响单个线程内的执行顺序 单个线程中,JMM仍然会对临界区的执行动作进行重排序,而顺序一致性并没有进行重排,仍然保持与程序代码相同的顺序
3. JMM规范梳理 共享数据规则
能够被多个线程共享的内存区域称为共享内存或是堆内存 线程共享数据: 所有的对象实例字段,static字段,数组元素等 线程封闭数据: 局部变量,方法参数,异常处理器以及ThreadLocal/ThreadLocalRandom等
线程操作规则
相当于线程行为可以被其他线程看到,也可以检测到其他线程的行为动作,程序行为表现如下: Synchronization原则(能够被感知,可见行为的变化)
监视器m的解锁与监视器m的后续动作加锁操作同步 线程对volatile变量v进行写操作,与任何线程对v的所有后续读操作同步 启动线程的操作与线程执行的第一个动作的操作同步 在线程中对每个属性执行默认值的写入操作与线程的第一个动作操作同步 线程中的最终动作T1 与另一个线程T2中检测到T1已终止的任何动作同步 如果线程T1中断thread T2,则该中断线程T1 将与 任何其他线程(包括T2)确定T2已被中断(通过InterruptedException引发或调用Thread.interrupted 或Thread.isInterrupted)的任何点同步
Happen-Before原则(规范)
执行动作之间的happen-before关系 如果两个动作x和y,我们定义hb(x,y)来描述x happen before y,满足关系有以下情况: 同一个线程中执行动作x和y,在程序顺序上x优先于y,则hb(x,y) 对象构造器代码块的结束happen-before该对象finalizer的开始 如果x动作与接下来的y动作同步,则hb(x,y) 传递性,如果hb(x,y),且hb(y,z),则hb(x,z)
happen-before原则 主要作用于两个的动作存在冲突的执行顺序以及定义数据竞争发生的时机,具体VM实现,遵循以下原则: 线程解锁动作都happen-before该线程的后续动作锁操作 对volatile变量执行写操作happen-before该变量读操作的后续每个动作 调用线程的start()方法happen-before于已开启的线程内的任何一个动作 线程所有动作happen-before于其他任意线程成功从该线程对象的join()方法返回 程序任何对象的初始化happen-before于程序中任何其他的动作操作行为
作用
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注天达云行业资讯频道,感谢您对天达云的支持。
|