【学习笔记】深入理解Java虚拟机学习笔记——第12章 Java内存模型与线程
第12章 Java内存模型与线程
12.1 概述
略
12.2 硬件的效率与一致性
计算机的计算速度比IO快几个数量级,为了消除这种差异,引入了高速缓存,但也带来了更高的复杂度
12.2.1 解释器与编译器
C1客户端编译器:优化力度小,编译快
C2服务端编译器:优化力度大,编译慢
12.3 Java内存模型
Java内存模型屏蔽了不同平台内存模型的差异
12.3.1 主内存与工作内存
12.3.2 内存间交互操作
8种操作及规则
12.3.3 对于volatile型变量的特殊规则
轻量级同步机制
可见性,读/写原子性,禁止指令重排(内存屏障)
12.3.4 针对long和double型变量的特殊规则
不适用volatile修饰的long与double,可能由于两次32位操作分解,而使并发读取,取到32位的“半个变量”值
12.3.5 原子性、可见性、有序性
1>原子性
基本类型访问、读写具备原子性
2>可见性
一个线程修改对其他线程可见【volatile、synchronized、final】
3>有序性
执行结果不变,执行顺序可变,但可禁止指令重排
12.3.6 先行发生原则
先行发生规则:HB P453
很多操作要求对之前的操作可观测,比如unlock与lock,不可能指令重排把unlock排在lock之前。
12.4 Java与线程
12.4.1 线程的实现
每一个调用过star()方法但未结束的Thread类就代表一个线程
1>内核线程实现
由内核支持调度,内核线程视为内核的一个分身,但实现时主要使用轻量级进程(与内核线程1:1)
2>用户线程实现
无内核支持,但不用切换内核态,由用户控制线程阻塞处理等(1:N)
3>混合实现
由轻量级进程充当内核与用户进程的桥梁(N:M)
4>Java线程的实现
主流使用内核线程实现
12.4.2 Java线程调度
1>协同式:线程执行完后主动让出
2>抢占式:由系统分配,可让出,但无需主动获取时间片
【线程优先级(Java)可以帮助系统分配时间,但无法完全信任,只是一个对系统的“建议”,且不同操作系统下的优先级映射情况不同】
12.4.3 状态转换
New:新建
Runnalbe:运行
Waiting:wait()、join()、park()
Timed Waiting:sleep、wait、join、park过期时间的方法
Blocked:排他锁阻塞
Terminated:结束执行
12.5 Java与协程
12.5.1 内核线程的局限
分布式场景下请求更多,响应更快,而传统线程池一般为几十个至两百个。线程切换损耗甚至接近于计算开销。
12.5.2 协程的复苏
协程最初为协同调度的用户线程,上下文切换由用户自己实现,而协同调度的实现又更简单,但后面已经出现了抢占式协程
12.5.3 Java的解决方案
loom期望使用有栈协程(纤程)来使用Java对于用户线程的并发实现,但未确定发布日期(2018)