Concurrency object creation in Java

梦想与她 提交于 2019-12-21 07:38:53

问题


I'm reading a book "Java concurrency in practice" by Brian Goetz. Paragraphs 3.5 and 3.5.1 contains statements that I can not understand.

Consider the following code:

public class Holder {
  private int value;
    public Holder(int value) { 
    this.value = value;
  }

  public void assertValue() {
    if (value != value) throw new AssertionError("Magic");
  }
}

class HolderContainer {
  // Unsafe publication
  public Holder holder;

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

Author states that:

  1. In Java, Object constructor first writes default values to all fields before subclass constructor run.
  2. Therefore it's possible to see field default value as a stale value.
  3. Thread may see stale value the first time it reads a field and then a more up-to-date value the next time, which is why assertN  can throw AssertionError.

So, according to the text, with some unlucky timing it is possible that value = 0; and in the next moment value = 42.

I agree with point 1 that Object constructor firstly fills fields with default values. But I don't understand points 2 & 3.

Let's update authors code and consider the following example:

public class Holder {
  int value;

  public Holder(int value) {
    //Sleep to prevent constructor to finish too early
    try {
     Thread.sleep(3000);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    this.value = value;
  }

  public void assertValue()  {
    if(value != value) System.out.println("Magic");
  }
}

I've added Thread.sleep(3000), to force thread to wait before object will be fully constructed.

public class Tests {

  private HolderContainer hc = new HolderContainer();

  class Initialization implements Runnable {
    public void run() {
      hc.init();
    }
  }

  class Checking implements Runnable {
    public void run() {
      hc.holder.assertValue();
    }
  }

  public void run() {
    new Thread(new Initialization()).start();
    new Thread(new Checking()).start();
  }
}

In example:

  1. first thread inits holder object
  2. second thread calls assertValue

Main Thread runs two threads:

  1. new Thread(new Initialization()).start(); It tooks 3 seconds to fully construct Holder object
  2. new Thread(new Checking()).start(); since Holder object still not constructed code will throw an NullPointerException

Therefore, it's impossible to emulate situation when field has default value.

My Questions:

  1. Author was wrong about this concurrency problem?
  2. Or It it impossible to emulate behaviour for fields default values?

回答1:


You are probably trying to simulate a concurrency scenario, which I believe is very hard to simulate using a couple of threads.

The following test-case which you have written is not correct at all is more likely to throw a NullPointerException.

public class Tests {

  private HolderContainer hc = new HolderContainer();

  class Initialization implements Runnable {
    public void run() {
      hc.init();
    }
  }

  class Checking implements Runnable {
    public void run() {
      hc.holder.assertValue();
    }
  }

  public void run() {
    new Thread(new Initialization()).start();  
    new Thread(new Checking()).start(); 
  }
}

What if your Checking Thread executes before Initialization one?? Also putting a sleep there simply means that executing thread will sleep and does tell you about the internal atomic operations being performed by then.




回答2:


Did not reproduce it with your code. Here is an example to emulate un-safe publication. The strategy is let one thread publication Holder and let another check its value.

class Holder {
    private volatile int value;

    public Holder(int value, HolderContainer container) {
        container.holder = this;  // publication this object when it is not initilized properly
        try {
            Thread.sleep(10);  
        } catch (Exception e) {

        }
        this.value = value; // set value
    }

    public int getValue() {
        return value;
    }
}

class HolderContainer {

    public Holder holder;

    public Holder getHolder() { 
        if (holder == null) { 
            holder = new Holder(42, this);
        }
        return holder;
    }
}


public class Tests {

    public static void main(String[] args) {
        for (int loop = 0; loop < 1000; loop++) {
            HolderContainer holderContainer = new HolderContainer();
            new Thread(() -> holderContainer.getHolder()).start();
            new Thread(() -> {
                Holder holder = holderContainer.getHolder();
                int value1 = holder.getValue();  // might get default value
                try {
                    Thread.sleep(10);
                } catch (Exception e) {

                }
                int value2 = holder.getValue(); // might get custom value
                if (value1 != value2) {
                    System.out.println(value1 + "--->" + value2);
                }
            }).start();
        }
    }

}


来源:https://stackoverflow.com/questions/50655856/concurrency-object-creation-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!