Java中的并发对象创建 [英] Concurrency object creation in Java
问题描述
我正在读Brian Goetz的一本书实践中的Java并发。第3.5和3.5.1段包含我无法理解的陈述。
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.
考虑以下代码:
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);
}
}
作者声明:
- 在Java中,对象构造函数首先在子类构造函数运行之前将默认值写入所有字段。
- 因此,可以将字段默认值视为陈旧值。
- 线程第一次读取字段时可能会看到陈旧值,然后是下次更新的值,这就是assertN可以抛出AssertionError的原因。
所以,根据文字,一些不幸的时机可能值= 0;在下一刻,值= 42。
So, according to the text, with some unlucky timing it is possible that value = 0; and in the next moment value = 42.
我同意第1点,即Object构造函数首先使用默认值填充字段。但我不明白第2点和第2点3。
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");
}
}
我添加了Thread.sleep(3000),强制线程在对象完全构造之前等待。
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();
}
}
例如:
- 第一个线程inits holder对象
- 第二个线程调用assertValue
主线程运行两个线程:
- new Thread(new Initialization())。start();完全构造Holder对象花了3秒钟
- 新线程(new Checking())。start();因为Holder对象仍然没有构造代码会抛出 NullPointerException
- new Thread(new Initialization()).start(); It tooks 3 seconds to fully construct Holder object
- 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.
我的问题:
- 作者对此并发性有误问题?
- 或者无法模拟字段默认值的行为?
推荐答案
没有使用您的代码重现它。以下是模拟不安全发布的示例。策略是让一个线程发布 Holder
并让另一个检查它的值。
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();
}
}
}
这篇关于Java中的并发对象创建的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!