Я просто наткнулся на статью, которая делает заявку, о которой я никогда не слышал, и не могу найти нигде. Утверждение состоит в том, что с точки зрения другого потока назначение значения, возвращаемого конструктором, может быть переупорядочено относительно инструкций внутри конструктора. Другими словами, утверждение состоит в том, что в приведенном ниже коде другой поток мог читать ненулевое значение a
, в котором значение x
не было установлено.
class MyInt {
private int x;
public MyInt(int value) {
x = value;
}
public int getValue() {
return x;
}
}
MyInt a = new MyInt(42);
Это правда?
Edit:
Я думаю, что это гарантировало, что с точки зрения потока, выполняющего MyInt a = new MyInt(42)
, присваивание x
имеет отношение до отношения с назначением a
. Но оба эти значения могут быть кэшированы в регистрах, и они не могут быть сброшены в основную память в том же порядке, в котором они были изначально написаны. Без барьера памяти другой поток может поэтому прочитать значение a
до того, как будет записано значение x
. Правильно?
Итак, основываясь на axtavt и последующих комментариях, соответствуют ли эти оценки безопасности потоков?
// thread-safe
class Foo() {
final int[] x;
public Foo() {
int[] tmp = new int[1];
tmp[0] = 42;
x = tmp; // memory barrier here
}
}
// not thread-safe
class Bar() {
final int[] x = new int[1]; // memory barrier here
public Bar() {
x[0] = 42; // assignment may not be seen by other threads
}
}
Если это правильно... ничего себе, это действительно тонкое.