java 重排序现象
我们需要了解初始化对象的过程,大致如下:
1. 分配内存空间
2. 初始化对象
3. 将对象指向分配的内存空间
有些编译器为了提升效率,会将 2 3 的顺序倒置(重排序,先将对象指向分配的内存空间再初始化),因此可能发生读取到未初始化完成的对象
下面看一个例子 (这里不考虑多线程问题):
在这个例子中 service 方法判断 bo 对象是否为 null, 若不为 null, 获取 attr 属性, 表面上看没有问题,若发生重排序现象,先将对象指向分配的内存空间,此时 bo 不为 null,但 attr 属性的赋值工作有可能还未完成(假设需要很长时间),则获取到的值为 null,遍历集合时就会出现空指针异常
public class Demo {private BO bo = new BO();
public void service() {if(bo != null) {List<String> attrs = bo.getAttr();// 若发生重排序, 这里取到的值会是 null
attrs.stream().forEach(attr -> {// 继续其他逻辑});
}
}
}
class BO{
public List<String> attr;
public BO() {attr = setAttr();
}
private List<String> setAttr() {
// 假设 getAttrs 是获取 attr 的方法
return getAttrs();}
public List<String> getAttr() {return this.attr;}
}
如何解决?
使用 volatile
关键字,禁止重排序
private volatile BO bo;