简体   繁体   English

Java Object 多线程环境下的构造

[英]Java Object Construction In Multi-Threaded Environment

I am reading this book called "Java Concurrency in Practice" and the author gives an example of an unsafe object publication.我正在阅读这本名为“Java Concurrency in Practice”的书,作者给出了一个不安全的 object 出版物的示例。 Here is the example.这是示例。

public Holder holder;

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

and

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.");
    }
}

So does this mean that other thread has access to an object when it is not even fully constructed?那么这是否意味着其他线程在 object 甚至还没有完全构建时可以访问它? I guess that when a thread A calls holder.initialize();我猜当线程 A 调用holder.initialize(); and thread B calls holder.assertSanity();和线程 B 调用holder.assertSanity(); the condition n != n will not be met if thread A has not yet executed this.n = n;如果线程 A 尚未执行this.n = n;则条件n != n将不成立

Does this also mean that if I have a simpler code like这是否也意味着如果我有一个更简单的代码

int n;

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

A problem can occur if the assertSanity method is pre-empted between the first and second load of n (the first load would see 0 and the second load would see the value set by the constructor).如果 assertSanity 方法在n的第一次和第二次加载之间被抢占,则可能会出现问题(第一次加载会看到0 ,第二次加载会看到构造函数设置的值)。 The problem is that the basic operations are:问题是基本操作是:

  1. Allocate space for the object为 object 分配空间
  2. Call the constructor调用构造函数
  3. Set holder to the new instanceholder设置为新实例

The compiler/JVM/CPU is allowed to reorder steps #2 and #3 since there are no memory barriers (final, volatile, synchronized, etc.)由于没有 memory 屏障(最终、易失性、同步等),因此允许编译器/JVM/CPU 重新排序步骤 #2 和 #3

From your second example, it's not clear if "n" is a local variable or a member variable or how another thread might be simultaneously mutating it.从您的第二个示例中,不清楚“n”是局部变量还是成员变量,或者另一个线程如何同时对其进行变异。

Your understanding is correct.你的理解是正确的。 That is exactly the problem the author seek to illustrate.这正是作者试图说明的问题。 There are no guards in Java that ensure an object is fully constructed prior to accessing in when multiple threads are concerned. Java 中没有任何防护措施可确保在涉及多个线程时在访问之前完全构建 object。 Holder is not thread-safe as it contains mutable state. Holder 不是线程安全的,因为它包含可变的 state。 The use of synchronization is required to fix this.需要使用synchronization来解决此问题。

I'm not sure I understand your 2nd example, it lacks context.我不确定我是否理解您的第二个示例,它缺乏上下文。

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

    }
}

This example result in "0 3" which means reference to an object could be used by another thread even before its constructor done.此示例导致“0 3”,这意味着对 object 的引用甚至可以在其构造函数完成之前被另一个线程使用。 You may find the rest answer here . 您可以在此处找到 rest 答案 Wish it could help.希望它可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM