JMM,定义了主存、工作内存抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等
体现在以下几个方面:
原子性:保证指令不会受到线程上下文切换的影响
可见性:保证指令不会受cpu缓存的影响
有序性:保证指令不会受cpu指令并行优化的影响

volatile(易变关键字):
他可以用来修饰成员变量和静态成员变量,他可以避免线程从自己的工作缓存中查找变量的值,必须到贮存中获取他的值,线程操作volatile变量都是直接操作主存

临界区内代码(加锁),也是直接操作主存

加锁是重量级操作,尽量使用volatile

但是加锁不仅保证可见性,也能保证原子性

根据 Java 内存模型(JMM) 的释放/获取(Release/Acquire)语义:

进入 synchronized 块:会清空当前线程的工作内存,强制从主内存中重新读取变量。

退出 synchronized 块:会把工作内存中的修改强制刷回主内存。

同步模式之Balking

Balking(犹豫)模式用在一个线程发现另一个线程或本线程已经做了某一件相同的事,那么本线程就无需在做了,直接结束返回。

有序性

JVM会在不影响正确性的前提下,可以调整语句的执行顺序
这种特性称之为指令重排

为什么指令重排:
在不改变程序结果的前提下,这些指令的各个阶段可以通过重排序和组合来实现指令级并行,这一技术在80中叶到90年代占据了计算架构的重要地位

volatile可以保证有序性

volatile原理

底层原理是内存屏障:
对volatile变量的写指令后会加入写屏障
对volatile变量的读指令前会加入读屏障

写屏障保证在该屏障之前的,对共享变量的改变,同步到主存中
读屏障保证再改屏障之后,对共享变量的读取,加载的是主存中最新数据

写屏障保证指令重排时,不会将写屏障之前的代码排在写屏障之后
读屏障会确保指令重排时,不会将读屏障之后的代码排在读屏障之前

happens-before规则

规定了对共享变量的写操作对其他线程的读操作可见性,他是可见性与有序性的一套规则总结

  • 线程解锁m之前对变量的写,对于接下来对m加锁的其他线程对该变量的读可见
  • 线程对volatile变量的写,对接下来其他线程对该变量的读可见
  • 线程start前对变量的写,对该线程开始后对该变量的读可见
  • 线程结束前对变量的写,对其他线程得知他结束后的读可见(比如其他线程调用isAlive()或join()等待它结束)
  • 线程t1打断t2前对变量的写,对于其他线程得知t2被打断后变量的读可见(通过t2.interrupted或t2.isInterrupted)
  • 对变量默认值的写,对其他线程对该变量的读可见
  • 具有传递性

防止反序列化

添加方法

public Object readResovle(){
	return 单例对象;
}

枚举:饿汉式、防反序列化、防反射

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐