Это демонстрирует переупорядочение определенных назначений, из 1M итераций обычно есть несколько напечатанных строк.
public class App {
public static void main(String[] args) {
for (int i = 0; i < 1000_000; i++) {
final State state = new State();
// a = 0, b = 0, c = 0
// Write values
new Thread(() -> {
state.a = 1;
// a = 1, b = 0, c = 0
state.b = 1;
// a = 1, b = 1, c = 0
state.c = state.a + 1;
// a = 1, b = 1, c = 2
}).start();
// Read values - this should never happen, right?
new Thread(() -> {
// copy in reverse order so if we see some invalid state we know this is caused by reordering and not by a race condition in reads/writes
// we don't know if the reordered statements are the writes or reads (we will se it is writes later)
int tmpC = state.c;
int tmpB = state.b;
int tmpA = state.a;
if (tmpB == 1 && tmpA == 0) {
System.out.println("Hey wtf!! b == 1 && a == 0");
}
if (tmpC == 2 && tmpB == 0) {
System.out.println("Hey wtf!! c == 2 && b == 0");
}
if (tmpC == 2 && tmpA == 0) {
System.out.println("Hey wtf!! c == 2 && a == 0");
}
}).start();
}
System.out.println("done");
}
static class State {
int a = 0;
int b = 0;
int c = 0;
}
}
Печать сборки для лямбды записи получает этот вывод (средипрочее ..)
; {metadata('com/example/App$$Lambda$1')}
0x00007f73b51a0100: 752b jne 7f73b51a012dh
;*invokeinterface run
; - java.lang.Thread::run@11 (line 748)
0x00007f73b51a0102: 458b530c mov r10d,dword ptr [r11+0ch]
;*getfield arg$1
; - com.example.App$$Lambda$1/1831932724::run@1
; - java.lang.Thread::run@-1 (line 747)
0x00007f73b51a0106: 43c744d41402000000 mov dword ptr [r12+r10*8+14h],2h
;*putfield c
; - com.example.App::lambda$main$0@17 (line 18)
; - com.example.App$$Lambda$1/1831932724::run@4
; - java.lang.Thread::run@-1 (line 747)
; implicit exception: dispatches to 0x00007f73b51a01b5
0x00007f73b51a010f: 43c744d40c01000000 mov dword ptr [r12+r10*8+0ch],1h
;*putfield a
; - com.example.App::lambda$main$0@2 (line 14)
; - com.example.App$$Lambda$1/1831932724::run@4
; - java.lang.Thread::run@-1 (line 747)
0x00007f73b51a0118: 43c744d41001000000 mov dword ptr [r12+r10*8+10h],1h
;*synchronization entry
; - java.lang.Thread::run@-1 (line 747)
0x00007f73b51a0121: 4883c420 add rsp,20h
0x00007f73b51a0125: 5d pop rbp
0x00007f73b51a0126: 8505d41eb016 test dword ptr [7f73cbca2000h],eax
; {poll_return}
0x00007f73b51a012c: c3 ret
0x00007f73b51a012d: 4181f885f900f8 cmp r8d,0f800f985h
Я не уверен, почему последние mov dword ptr [r12+r10*8+10h],1h
не помечены путфилдом b и строкой 16, но вы можете увидеть поменявшиеся присвоения b и c (c сразу после a).
РЕДАКТИРОВАТЬ: Поскольку записи происходят в порядке a, b, c и чтения происходят в обратном порядке c, b, a, вы никогда не должны видеть недопустимое состояние, если только записи (или чтения)переупорядочены.
Записи, выполняемые одним процессором (или ядром), видны всем процессорам в одинаковом порядке, см., Например, этот ответ , который указывает на Руководство по системному программированию Intel Том 3раздел 8.2.2.
Запись одним процессором наблюдается в одном и том же порядке всеми процессорами.