Java学习总结(1.2.1) Java内存模型详解

精贴 置顶
1512 0
作者:      发布时间: 2020-03-18 11:10:59

Java语言规范 --  Java内存模型  (提出规则 )

Java虚拟机规范 -- Jvm运行时数据区 (实现规则 )


Java内存模型

>前面章节中的大部分讨论仅涉及代码的行为,即一次执行单个语句或表达式,即通过单个线程来执行。Java虚拟机可以同时支持多个执行线程,若未正确同步,线程的行为可能会出现混淆和违反直觉。

>本章描述了多线程程序的语义;它包含了,当多个线程修改了共享内存中的值时,应该读取到哪个值的规则。由于这部分规范类似于不同硬件体系结构的内存模型,因此这些语义称为Java编程语言内存模型。

>这些语义没有规定如何执行多线程程序。相反,它们描述了允许多线程程序的合法行为。

                                     --《Java语言规范》 translated by James



多线程中的问题

1、所见非所得

2、无法肉眼去检测程序的准确性

3、不同的运行平台有不同的表现

4、错误很难重现



高速缓存有可见问题(3S)


CPU指令重排序 

Java编程语言的语义允许Java编译器和微处理器进行执行优化,这些优化导致了与其交互的代码不再同步,从而导致看似矛盾的行为。

as-if-serial

只保证单个线程执行



JIT编辑器(Just In Time Compiler)

脚本语言与编译语言的区别?

解释执行:即咱们说的脚本,在执行时,由语言的解释器将其一条条翻译成机器可识别的指令。(一条条地编译)

编译执行:将我们编写的程序,直接编译成机器可以识别的指令码。(打包一次性地编译)


Java是脚本语言还是编译语言?

两者都有


当代吗重复多次执行时,解释执行存在性能问题



JIT性能优化:过于激进的性能优化


bool f = isRunning

if (f){

    while(true){

        i++

    }

}

把isrunning的值存起来




volatile关键字

可见性问题:让一个线程对共享变量的修改,能够及时的被其他线程看到。

Java内存模型规定对 volatile変量v的写入,与所有其他线程后续对v的读同步

要满足这些条件,所以 volatile关键字就有这些功能:

  1. 禁止缓存:volatile变量的访问控制符会加个 ACC VOLATILE

    https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5

  2. 对 volatile变量相关的指令不做重排序;


禁止JIT部分缓存

volatile 保证可见性问题


Shared Variables定义

可以在线程之间共享的内存称为共享内存或堆内存。

所有实例字段、静态字段和数组元素都存储在堆内存中,这些字段和数组都是标题中提到的共享变量。

冲突:如果至少有一个访问是写操作,那么对同一个変量的两次访问是冲突的。

这些能被多个线程访问的共享变量是内存模型规范的对象。


线程间操作的定义

1、线程间操作指:一个程序执行的操作可被其他线程感知或被其他线程直接影响。

2、Java内存模型只描述线程间操作,不描述线程内操作,线程内操作按照线程内语义执行。


所有线程间操作,都存在可见性问题,JMM需要对其进行规范



对于同步的规则定义

对 volatile变量v的写入,与所有其他线程后续对ν的读同步

对于监视器m的解锁与所有后续操作对于m的加锁同步

对于每个属性写入默认值(0, false,null)与每个线程对其进行的操作同步

启动线程的操作与线程中的第一个操作同步

线程T2的最后操作与线程T1发现线程T2已经结束同步。( isalive, join可以判断线程是否终结)

如果线程T1中断了T2,那么线程T1的中断操作与其他所有线程发现T2被中断了同步通过抛出 Interruptedexception异常,或者调用 Thread. interrupted或 Thread. interrupted



Happens- before先行发生原则

happens- before关系用于描述两个有冲突的动作之间的顺序,如果一个 action happends before另一个 action,则第一个操作被第二个操作可见,JVM需要实现如下 happens- before规则:

>某个线程中的每个动作都 happens-before该线程中该动作后面的动作。

>某个管程上的 unlock i动作 happens-before同一个管程上后续的1ock动作

>对某个 volatile字段的写操作 happens- before每个后续对该 volatile字段的读操作

>在某个线程对象上调用 start(方法 happens- before被启动线程中的任意动作

>如果在线程t1中成功执行了t2. join(),则t2中的所有操作对t1可见

>如果某个动作 a happens-before 动作 b,且 b happens-before 动作 c,则有 a happens-before c.


当程序包含两个没有被 happens- before关系排序的冲突访问时,就称存在数据竞争。遵守了这个原则,也就意味着有些代码不能进行重排序,有些数据不能缓存!




总结:

JMM是对java语言的多线程进行描述,得出一些规则,最终由JVM来实现。

由于CPU和JVM底层遗留的问题,CPU的高速缓存和JVM的优化机制,所以需要 JMM制定一些规则。

volatile来解决问题,方法:不用JVM缓存









标签:

每日一句

如果花了足够多的时间考虑你的目标,你就能用自己的心看到、摸到、尝到和闻到那个目标,你不会轻易放弃。实现目标的欲望会给你足够的毅力克服哪怕是最令人生畏的障碍。在真的取得成功之前,你应该已经在头脑中达成目标。这样你就能承受任何暂时的痛苦,实现自己的梦想。

标签云

vue
最近综合
情绪巨婴是什么 12.18
普通蛋糕做法 05.31
玉米烤肠芝士面包做法 05.31
Mysql安装教程 - 绿色版 06.18
我们学习知识为什么总是忘记呢?【学习金字塔】 05.12
Typora开发版⽆法使⽤解决⽅法 05.04
为什么无知者越自信? -- 达克效应 05.10
马斯洛需求层次理论 04.29
随机综合
Java学习总结(1.1.6) 线程封闭 03.19
中间件1.2.2-ActiveMQ支持的消息协议讲解 04.23
Java学习总结(1.2.1) Java内存模型详解 03.18
电商运营主要做什么? 10.08
android TextView标签字体加粗的几种方法 04.08
中间件1.3.3-RabbitMQ持久化机制、内存/磁盘控制 04.29
中间件1.2.1-ActiveMQ入门 04.22
Jquery Boxy的基本使用方法 01.28