我正在阅读Fred Long的 Java Concurrency Guidelines 中的不可变对象和线程安全性。
以下是本书的代码段。
// Immutable Helper
public final class Helper {
private final int n;
public Helper(int n) {
this.n = n;
}
// ...
}
// and a mutable Foo class:
final class Foo {
private Helper helper;
public Helper getHelper() {
return helper;
}
public void setHelper(int num) {
helper = new Helper(num);
}
}
代码段后面是解释:
getHelper()方法发布可变助手字段。因为 Helper类是不可变的,它不能被改变 初始化。此外,因为Helper是不可变的,所以它总是如此 在其参考可见之前正确构建 符合指南“TSM03-J。不要部分发布 初始化对象“,第162页。
现在让他们打开他们已经提到过的第162页。这是另一个代码段。
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;
}
}
接着是它自己的解释:
如果一个线程在之前使用getHelper()方法访问帮助器 已经调用了initialize()方法,线程会观察到一个 未初始化的辅助领域。以后,如果一个线程调用initialize() 另一个调用getHelper(),第二个线程可能会观察其中一个 以下内容:
- 帮助程序引用为NULL,
- 完全初始化的Helper对象,n字段设置为42,
- 部分初始化的Helper对象,未初始化的n包含默认值0。
所以,不要把我大胆的两个陈述相互矛盾?
A编写了一段代码来测试案例,运行了几次,从未得到过0.只有null或42.这是我的代码:
package com.sample;
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
Foo foo = new Foo();
Initer initer = new Initer(foo);
Getter getter = new Getter(foo);
initer.start();
getter.start();
}
}
static class Getter extends Thread {
private Foo foo;
Getter(Foo foo) {
this.foo = foo;
}
@Override
public void run() {
System.out.println(foo.getHelper());
}
}
static class Initer extends Thread {
private Foo foo;
Initer(Foo foo) {
this.foo = foo;
}
@Override
public void run() {
foo.initialize();
}
}
static class Foo {
private Helper helper;
public Helper getHelper() {
return helper;
}
public void initialize() {
helper = new Helper(42);
}
}
public static class Helper {
private int n;
public Helper(int n) {
this.n = n;
}
@Override
public String toString() {
return Integer.toString(n);
}
}
}
答案 0 :(得分:2)
这两个陈述并不矛盾。如果第一个示例,则字段n
为final
。这就是Helper
类不可变的原因。在第二个示例中,n
不是final,Helper
不是不可变的,这意味着可以返回部分初始化的实例。
就你的代码观察这一点而言,彼得是对的,在实践中很难进行测试有几个原因。
答案 1 :(得分:1)
除非字段为final
,否则无法保证该值可见,
println
,它有自己的内存障碍,这会让您更难看到任何不一致。