指令重排
什么是指令重排
CPU 为了提高指令执行效率,在执行某些耗时的指令(比如从内存中读取数据)时,会同时去执行其他与这条指令没有依赖关系的指令,使得原本的指令执行顺序改变
指令重排带来的问题
对于单线程而言指令重排几乎不会带来任何影响,因为指令重排的前提是保证串行语义执行的一致性,不能影响最终的结果,但对于多线程环境而言,指令重排就可能导致严重的程序轮序执行问题
如何禁止指令重排
使用 volatile 关键字
volatile 是如何禁止指令重排的
通过插入内存屏障禁止在内存屏障前后的指令执行重排序优化
参考:https://baijiahao.baidu.com/s?id=1709086005694976168&wfr=spider&for=pc
synchronized 实现细节
public class SynChronizedDemo {
void method(){
synchronized (this){
}
}
public static void main(String[] args) {
}
}
通过 Jclasslib 工具查看 .class 解释后的指令:
0 aload_0
1 dup
2 astore_1
3 monitorenter
4 aload_1
5 monitorexit
6 goto 14 (+8)
9 astore_2
10 aload_1
11 monitorexit
12 aload_2
13 athrow
14 return
同一时刻 monitorenter monitorexit 之间的代码只允许一个线程访问
对象创建过程
- class loading :将 .class文件加载到内存
- class linking:
- verfication : 核实.class文件是否符合JVM规范
- preparation:给class静态变量赋默认值
- resolution
- initializing:静态变量赋初始值
- 给对象申请内存
- 成员变量赋默认值
- 调用构造方法(init)
- 多个成员变量按照顺序赋初始值
- 执行构造方法语句
对象在内存中的存储布局
MarkWord:标记字段,用于存储对象锁信息(如锁状态,当前对象被哪个线程锁住)
对齐填充: CPU读取内存数据时按照8的倍数读取效率更高,如果对象存储长度不符合就填充
对象定位
T t = new T();
-
句柄池
实例对象引用和 T.class 对象引用放入句柄池中,引用 t 指向句柄池 -
直接指针
引用 t 指向实例对象,实例对象中有一个引用指向 T.class 对象