Ответ 1
Альфа. Книга Paul E. McKenney Является ли параллельное программирование жестким, а если так, что вы можете с этим сделать? есть глава, объясняющая thememory model of the most важных платформ.
Я пытаюсь воспроизвести проблему видимости памяти в случае недостаточной инициализации объекта для нефинализированных полей (JLS 17.5 Final Field Semantics, FinalFieldExample). Там, где оно указано "Однако, f.y не является окончательным, поэтому метод reader() не гарантирует, что для него значение"
Я пробовал этот код:
public class ReorderingTest2 {
public static void main(String[] args) {
for (int i = 0; i < 2500; i++) {
new Thread(new Reader(i)).start();
new Thread(new Writer(i)).start();
}
}
static class Reader implements Runnable {
private String name;
Reader(int i) {
this.name = "reader" + i;
}
@Override
public void run() {
//System.out.println(name + " started");
while (true) {
FinalFieldExample.reader(name);
}
}
}
static class Writer implements Runnable {
private String name;
Writer(int i) {
this.name = "writer" + i;
}
@Override
public void run() {
//System.out.println(name + " started");
while (true) {
FinalFieldExample.writer();
}
}
}
static class FinalFieldExample {
int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}
static void writer() {
f = new FinalFieldExample();
}
static void reader(String name) {
if (f != null) {
int i = f.x;
int j = f.y;
if (i != 3 || j != 4) {
System.out.printf("reader %s sees it!%n", name);
}
}
}
}
}
Как и в предыдущей моей схожей теме - Я пробовал на разных компьютерах (от 2 до 8 ядер) с Windows и даже на нашей серверной ОС Solaris 32 box - я не смог воспроизвести его: fx и fy - всегда уже правильно инициализированы.
Для архитектуры Intel/x86/x64 как Я получил ответ - у них довольно много default memery гарантирует, которые предотвращают переупорядочение логики конструктора. Кажется, это тоже верно для Solaris/sparc?
Итак, в какой архитектуре/ОС это переупорядочение может быть воспроизведено?
Альфа. Книга Paul E. McKenney Является ли параллельное программирование жестким, а если так, что вы можете с этим сделать? есть глава, объясняющая thememory model of the most важных платформ.
Чтобы получить желаемый результат, вы можете попытаться включить большую оптимизацию, поэтому запустите программу в режиме -server
.
Сначала я подумал о создании f
volatile
, но это, очевидно, завело бы весь эксперимент.
Включите ведение журнала XML для компилятора "точно в момент времени" (если вы используете JVM HotSpot) и посмотрите на сгенерированный машинный код (используя какой-то внешний отладчик или самозагрузчик). Затем вы можете просмотреть сгенерированный код, если это даже позволит вам наблюдать за желаемым результатом.
Я предлагаю вам приобрести копию "Java Concurrency на практике" и прочитать главу 3, в которой подробно описаны гарантии JVM по поводу блокировки и видимости. Ваш вопрос не имеет ничего общего с конкретной архитектурой, и все, что нужно делать с пониманием, происходит раньше, чем в Java.
Я думаю, что вы не можете перепрограммировать проблему, потому что в конце конструктора FinalFieldExample есть до-крайний край, который гарантирует, что x = 3 и y = 4;
BTW. Объект FinalFieldExample немного беспорядок. Он хочет быть подходящим синглтоном, но вы его не кодировали. Отсутствие синхронизации вокруг статического "f" усложняет работу, поскольку это должно объяснять поведение во время выполнения этого класса. Понятно, что это должен быть правильный синглтон с синхронизацией, защищающий доступ к статическому "f", и вы должны называть методы записи и чтения, такие как...
FinalFieldExample.getInstance() Автор();.
Просто скажи
Возможно, это должен быть отдельный вопрос... но он очень точен. Это более экспансивная версия комментария, который я сделал ранее.
В первой части раздела 17.4 из jls говорится:
Чтобы определить, законны ли действия потока t при выполнении, мы просто оценить реализацию потока t, поскольку он будет выполняться в одном который определяется в остальной части этой спецификации.
Место, где я повесил трубку, понимает, что "как определено в остальной части этой спецификации" означает в отношении порядка программы.
В данном случае назначение
f = new FinalFieldExample();
подчиняется семантике присваивания (раздел 15.26.1), из которых следующее. Это смехотворно неверно отформатировано в спецификации (на третьем этапе особенно), я считаю, что я переформатировал его, чтобы точно отразить намерение.
[В противном случае, требуется три шага :
Это читается как спецификация однопоточного "заказа программы" для меня. Что я неправильно истолковываю?
Возможно, ответ заключается в том, что действительно предназначен "тест утки" - если один поток выполняет , как если бы все было сделано в указанном порядке, это правильная реализация. Но этот раздел написан совершенно иначе, чем в других местах, где это видно из-за использования этого слова, например:
Язык программирования Java также гарантирует, что каждый операнд оператора (кроме условных операторов &, ||, и?:) появляется для полной оценки до любой части операции сам выполняется.