我正在使用谷歌翻译阅读"SEI CERT Oracle编码标准的Java“。
其中一个建议是TSM03-J.不要发布部分初始化的对象,它给出了将导致“发布部分初始化对象”的代码。
我想重现文章中提到的错误,但失败了。谁能给我举个例子吗?
不要与下面的场景混淆,尽管它也可以得到部分初始化的对象。TSM01 01-J.在对象构造过程中不要让此引用转义。
class Foo {
private Helper helper;
public Helper getHelper() {
return helper;
}
public void initialize() {
helper = new Helper(42);
}
}
public class Helper {
private int n;
public Helper(int n) {
this.n = n;
}
// ...
}然后在那一页上有解释
如果一个线程在执行initialize()方法之前使用getHelper()方法访问助手,那么该线程将观察到一个未初始化的助手字段。稍后,如果一个线程调用initialize(),另一个调用getHelper(),则第二个线程可以观察到以下情况之一:
为了测试目的,我在"Helper“中添加了以下代码
public int getN() {
return n;
}下面是测试代码,我认为测试代码会输出“发布部分初始化的对象”,但是什么也没有发生。
public class Program {
public static void main(String[] args) {
boolean getZero = false;
while (!getZero) {
Foo foo = new Foo();
new Thread(foo::initialize).start();
while (true) {
Helper helper;
if ((helper = foo.getHelper()) != null) {
if (helper.getN() == 0) {
getZero = true;
System.out.println("publish partially initialized objects");
}
break;
}
}
}
}
}如何重现代码规范中提到的多线程错误?
发布于 2019-12-20 07:34:16
从同一页,
特别是,JMM允许编译器为新Helper对象分配内存,并在初始化新helper对象之前将对该内存的引用分配给Helper字段。换句话说,编译器可以重新排序对helper实例字段的写和初始化Helper对象(即that .n= n)的写,这样前者就会先发生。--这可以公开一个竞赛窗口,在此期间,其他线程可以观察到一个部分初始化的Helper对象实例。
要在这里观察部分初始化的对象,您的代码需要在读取foo.getHelper().getN()时点击这个争用窗口。你可以运行它数百万次,但仍然没有发生这种情况。就像大多数与多线程相关的错误一样,复制起来也不容易。
https://stackoverflow.com/questions/59419247
复制相似问题