У меня есть следующий образец кода:
class Shared {
int x;
int y;
void increment() {
x++;
y++;
}
void check() {
if (y > x) {
System.out.println("Ooops! y > x");
}
}
}
Выглядит ясно? Но главная проблема возникает здесь, когда я пытаюсь увеличить и проверить в двух потоках:
Shared shared = new Shared();
Thread writer = new Thread(() -> {
for (int i = 0; i < N; i++) {
shared.increment();
}
});
Thread reader = new Thread(() -> {
for (int i = 0; i < N; i++) {
shared.check();
}
});
writer.start();
reader.start();
Вы можете заметить гонку данных (в некоторых случаях переупорядочивание инструкций?):
1. x++;
2. y++;
И теперь я знаю о специальных флагах ВМ, которые могут помочь мне распечатать журналы JIT-компилятора (-XX:+PrintCompilation
).
...
120 181 3 Shared::increment (21 bytes)
120 182 3 Shared::check (20 bytes)
120 183 4 Shared::increment (21 bytes)
120 184 4 Shared::check (20 bytes)
121 181 3 Shared::increment (21 bytes) made not entrant
121 182 3 Shared::check (20 bytes) made not entrant
121 185 n 0 java.lang.invoke.MethodHandle::linkToStatic(L)L (native) (static)
121 184 4 Shared::check (20 bytes) made not entrant
122 186 3 Shared::check (20 bytes)
122 187 n 0 java.lang.Object::clone (native)
122 188 4 Shared::check (20 bytes)
122 189 % 3 Main::lambda$main$0 @ 2 (19 bytes)
122 190 3 Main::lambda$main$0 (19 bytes)
123 186 3 Shared::check (20 bytes) made not entrant
...
ОК, теперь я могу видеть, как обрабатывается компиляция метода приращения:
120 181 3 Shared::increment (21 bytes)
120 183 4 Shared::increment (21 bytes)
121 181 3 Shared::increment (21 bytes) made not entrant
Правильно ли я понимаю , что переупорядочение здесь происходит из-за многоуровневой компиляции ? Поскольку increment()
- горячий метод, JIT-компилятор профилирует эту информацию и использует C2
серверный компилятор. И, как мне кажется, таким образом переупорядочить некоторые инструкции, но в некоторых случаях происходит оптимизация (made not entrant
). Или это неправильно?
Также есть еще какие-то логи для компиляции:
138 182 2 Shared::increment (21 bytes)
138 184 4 Shared::increment (21 bytes)
138 182 2 Shared::increment (21 bytes) made not entrant