我有下一个代码示例:
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++;
现在,我了解特殊的VM标志,这可以帮助我打印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
我理解正确吗?>>,这里的重新排序是由于tiered compilation?因为increment()
-hot方法,所以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
我有下一个代码示例:Class Shared {int x;诠释无效的增量(){x ++; y ++; } void check(){if(y> x){System.out.println(“ ...
我理解正确吗,这里的重新排序是由于分层编译引起的?