引子
cpu会对代码进行优化,导致真正执行起来的顺序和我们想的可能不一样。经典的一道面试题就是单例模式为什么要用DBL,并且要不要加volatile
volatile保证了线程之间的可见性,也能防止指令重排。创建对象的具体过程可以通过javap -c看看字节码
创建对象
1. 开辟内存空间
2. 调用构造方法进行初始化
3. 将对象的引用存入局部变量表
当第2步和第3步发生了指令重排后,就会出现问题(仅仅针对单例模式这个面试题来说)
怎么防止指令重排序
这其实也是一道频率极高的面试题volatile为什么能禁止指令重排
在两条指令中间加内存屏障
// TODO 后续详细补充内存屏障的知识
happens-before
面试场合也会谈起这个东东,jvm强调的8种不能发生指令重排的场景。
as if serial
面试场合也会谈起这个东东,这句英文意思就是,仿佛是串行化
什么意思呢,发生指令重排就发生呗,但是在单线程下最后的效果和没发生一样
引申一下
通过as if serial想到一个场景题,来了一些任务,如何让他们挨着排执行,用一个jdk提供好的线程池Executors.newSingleThreadExecutor()
越看越多,我发现newSingleThreadExecutor注释中有这么一句话

🤔,newSingleThreadExecutor和newFixedThreadPool(1)区别是啥?
其实还是有细微的区别的。ThreadPoolExecutor这个类有一些API能够对线程池进行重新配置,比如:

再看看newSingleThreadExecutor里面做了什么?

包装了一层,削弱了一些能力,也就是Unlike the otherwise equivalent newFixedThreadPool(1) the returned executor is guaranteed not to be reconfigurable to use additional threads.