「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战」。
概述
由于现代计算机的运行速度和它的存储和通信子系统的速度差距太大,大量时间都花在磁盘I/O、网络通信以及数据库访问上,为了尽可能的利用计算机处理器的运算能力,于是就产生了让计算机同时处理几项任务等高效并发的想法。
物理设计中的并发
物理机中的并发情况和虚拟机中的并发情况有很多相似之处,物理机中如何处理并发对虚拟机实现并发有比较大的参考意义。
由于计算机的存储设备和处理器的运算速度有几个数量级的差距,所以现代计算机系统基本上都会加入高速缓存(Cache) 来作为内存和处理器之间的缓冲。具体过程类似:先将运算要用到的数据读取到高速缓存中进行运算,运算完成了之后在缓存同步到内存中,在这期间处理器可以继续执行其他的操作而不用等待内存读写了。
高速缓存虽然有效的缓解了存储设备和处理器运算速度之间的问题,不过它导致在共享内存多核系统中可能会产生缓存不一致的情况,也就是缓存一致性问题。
Java内存模型
Java内存模型必须定义的足够严谨,这样Java并发内存访问操作不会产生歧义,但是也需要定义的足够宽松,这样虚拟机的实现才能有足够的自由空间去利用硬件的各种特性来获取更好的执行速度。
主内存与工作内存
Java内存模型的主要目的是定义程序中各种变量的访问规则,关注变量值存储到内存和从内存中取出变量值的底层细节。此外Java内存模型规定所有变量存储在主内存中。每条线程还有其工作内存,该工作内存中保存了该线程使用的变量的主内存副本 (该副本保存的仅仅是该变量的引用或该变量某个线程访问的字段),线程对变量的所有操作必须在工作内存中进行。不同线程之间不能直接访问其工作内存,线程之间的变量值传递需要通过主内存。线程、主内存、工作内存三者的关系如下图所示:
内存间的交互操作
内存间的交互协议也就是一个变量如何从主内存拷贝到工作内存以及如何从工作内存同步回主内存这一类的实现细节。Java模型中定义了以下八种操作来完成上述协议。
-
lock:作用主内存的变量,把一个变量标识为一条线程独占的状态
-
unlock:作用于主内存的变量,释放被锁定的变量。
-
read:作用于主内存的变量,把一个变量的值从主内存读取到工作内存。
-
load:作用于工作内存的变量,把read操作读取到的变量放入工作内存的变量副本中。
-
use:作用于工作内存的变量,把工作内存中的一个变量的值传递给执行引擎。
-
assign:作用于工作内存的变量,把一个从执行引擎接受的值赋给工作内存的变量
-
store:作用于工作内存的变量,把工作内存中一个变量的值传递到主内存中,以便随后的write操作使用。
-
write:作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。