Java并发之Java内存模型

目录

主内存与工作内存

内存间交互操作

内存模型三大特征

先行发生原则


Java 内存模型试图屏蔽各种硬件和操作系统的内存访问差异,以实现让 Java 程序在各种平台下都能达到一致的内存访问效果。

主内存与工作内存

所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。

线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。

内存间交互操作

Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。

  • read:把一个变量的值从主内存传输到工作内存中
  • load:在 read 之后执行,把 read 得到的值放入工作内存的变量副本中
  • use:把工作内存中一个变量的值传递给执行引擎
  • assign:把一个从执行引擎接收到的值赋给工作内存的变量
  • store:把工作内存的一个变量的值传送到主内存中
  • write:在 store 之后执行,把 store 得到的值放入主内存的变量中
  • lock:作用于主内存的变量
  • unlock

内存模型三大特征

1.原子性

int 等原子性的类型在多线程环境中不会出现线程安全问题(错误)

AtomicInteger 能保证多个线程修改的原子性。

除了使用原子类之外,也可以使用 synchronized 互斥锁来保证操作的原子性。它对应的内存间交互操作为:lock 和 unlock,在虚拟机实现上对应的字节码指令为 monitorenter 和 monitorexit。

2.可见性

可见性指当一个线程修改了共享变量的值,其它线程能够立即得知这个修改。Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。

主要有三种实现可见性的方式:

  • volatile(volatile 并不能保证操作的原子性。)
  • synchronized,对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。
  • final,被 final 关键字修饰的字段在构造器中一旦初始化完成,并且没有发生 this 逃逸(其它线程通过 this 引用访问到初始化了一半的对象),那么其它线程就能看见 final 字段的值。

3.有序性

有序性是指:在本线程内观察,所有操作都是有序的。在一个线程观察另一个线程,所有操作都是无序的,无序是因为发生了指令重排序。在 Java 内存模型中,允许编译器和处理器对指令进行重排序,重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。

①volatile 关键字通过添加内存屏障的方式来禁止指令重排

②synchronized 保证每个时刻只有一个线程执行同步代码,相当于是让线程顺序执行同步代码,达到有序性。

先行发生原则

JVM 还规定了先行发生原则,让一个操作无需控制就能先于另一个操作完成。

1.单一线程原则

在一个线程内,在程序前面的操作先行发生于后面的操作。

2.管理锁定规则

一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。

3.volatile变量原则

对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。

4.线程启动规则

Thread 对象的 start() 方法调用先行发生于此线程的每一个动作。

5.线程加入规则

Thread 对象的结束先行发生于 join() 方法返回。

6.线程中断规则

对线程 interrupt() 方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过 interrupted() 方法检测到是否有中断发生。

7.对象终结规则

一个对象的初始化完成(构造函数执行结束)先行发生于它的 finalize() 方法的开始。

8.传递性

如果操作 A 先行发生于操作 B,操作 B 先行发生于操作 C,那么操作 A 先行发生于操作 C。

发布了15 篇原创文章 · 获赞 1 · 访问量 773

猜你喜欢

转载自blog.csdn.net/trytrylmt/article/details/104080979