以下摘自某教程:
有序性指的是程序按照代码的先后顺序执行。而编译器为了优化性能,有时候会改变程序中语句的先后顺序。
Java 中经典的案例就是利用双重检查创建单例对象,其中 volatile
就是保证有序性的。
public class Singleton {
private static volatile Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
如果没有 volatile
,我们以为的 new 操作应该是:
但是实际上优化后的执行路径却是这样的:
假设线程 A 先执行 getInstance()
方法,当执行完指令 2 时恰好发生了线程切换,切换到了线程 B 上;如果此时线程 B 也执行 getInstance()
方法,那么线程 B 在执行第一个判断时会发现 instance != null
,所以直接返回 instance ,而此时的 instance 是没有初始化过的,如果我们这个时候访问 instance 的成员变量就可能触发空指针异常。
问题:线程 A 在 new 之前获取了锁,为啥线程 B 还可以访问?
查资料有人说经过这两步 1.分配一块内存 M ; 2. 将 M 的地址赋值给 instance 变量;
后就会释放锁,不知道对不对
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.