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

多线程环境下的Java对象构造,java,multithreading,object,concurrency,Java,Multithreading,Object,Concurrency,我正在阅读这本名为《Java并发实践》的书,作者给出了一个不安全对象发布的示例。这是一个例子 public Holder holder; public void initialize(){ holder = new Holder(42); } 及 那么,这是否意味着当对象还没有完全构造好时,其他线程可以访问该对象呢?我猜当线程a调用holder.initialize()时和线程B调用holder.assertSanity()条件n!=如果线程A尚未执行此操作,则不会满足n。n=n 这是

我正在阅读这本名为《Java并发实践》的书,作者给出了一个不安全对象发布的示例。这是一个例子

public Holder holder;

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

那么,这是否意味着当对象还没有完全构造好时,其他线程可以访问该对象呢?我猜当线程a调用
holder.initialize()时和线程B调用
holder.assertSanity()条件
n!=如果线程A尚未执行此操作,则不会满足n
。n=n

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

int n;

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

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

  • 为对象分配空间
  • 调用构造函数
  • holder
    设置为新实例
  • 编译器/JVM/CPU可以对步骤2和步骤3重新排序,因为没有内存障碍(final、volatile、synchronized等)


    在第二个示例中,不清楚“n”是局部变量还是成员变量,也不清楚另一个线程如何同时对其进行变异。

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

    我不确定我是否理解您的第二个示例,它缺少上下文

    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”,这意味着对一个对象的引用甚至在它的构造函数完成之前就可以被另一个线程使用。希望能有所帮助

    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();
            }
    
        }
    }