多线程环境中的Java对象构造

时间:2011-06-07 17:23:40

标签: java multithreading object concurrency

我正在阅读这本名为“Java Concurrency in Practice”的书,作者给出了一个不安全的对象出版物的例子。这是一个例子。

public Holder holder;

public void initialize(){
   holder = new Holder(42);
}

public class Holder {
    private int n;
    public Holder(int n) { this.n = n; }
    public void assertSanity() {
        if (n != n)
            throw new AssertionError("This statement is false.");
    }
}

这是否意味着其他线程在完全构造时无法访问对象?我想当线程A调用holder.initialize();而线程B调用holder.assertSanity();时,如果线程A尚未执行n != n

,则不会满足条件this.n = n;

这是否意味着如果我有一个更简单的代码,如

int n;

System.out.println(n == n); //false?

3 个答案:

答案 0 :(得分:3)

如果在n的第一次加载和第二次加载之间抢占了assertSanity方法,则会出现问题(第一次加载会看到0,第二次加载会看到构造函数设置的值)。问题是基本操作是:

  1. 为对象分配空间
  2. 调用构造函数
  3. holder设置为新实例
  4. 允许编译器/ JVM / CPU重新排序步骤#2和#3,因为没有内存屏障(最终,易失,同步等)

    从你的第二个例子来看,不清楚“n”是局部变量还是成员变量,或者另一个线程是如何同时改变它的。

答案 1 :(得分:1)

您的理解是正确的。这正是作者试图说明的问题。 Java中没有保护措施可以确保在涉及多个线程时访问之前完全构造对象。持有者不是线程安全的,因为它包含可变状态。需要使用synchronization来解决此问题。

我不确定我理解你的第二个例子,它缺乏背景。

答案 2 :(得分:0)

public static void main(String[] args) {

    A a = new A();
    System.out.println(a.n);

}

static class A{
    public int n;

    public A(){

        new Thread(){

            public void run() {
                System.out.println(A.this.n);
            };

        }.start();

        try {
            Thread.currentThread().sleep(1000);
            n=3;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

此示例导致“0 3”,这意味着即使在构造函数完成之前,另一个线程也可以使用对对象的引用。 You may find the rest answer here。希望它可以提供帮助。