我有一个方法,看起来像是由 JIT 重新排序的。
public boolean finishRequest(boolean success) {
if (success) {
error = false;
wayPoints.put(FINISH_SUCCESS_WP, System.currentTimeMillis());
} else {
wayPoints.put(FINISH_ERROR_WP, System.currentTimeMillis());
error = true;
}
someThread.addToQueue(this);//...submit for further processing on separate thread
return true;
}
wayPoints 容器是“this”的一个字段,由 someThread 访问。当通过 getWayPoints() 迭代此' wayPoints 时,我最终在 someThread 内的某行代码中得到了 ConcurrentModificationException。
为了解决这个问题,我创建了一个新的不可变类,它将传递给 someThread 而不是“this”。
public boolean finishRequest(boolean success) {
if (success) {
error = false;
wayPoints.put(FINISH_SUCCESS_WP, System.currentTimeMillis());
} else {
wayPoints.put(FINISH_ERROR_WP, System.currentTimeMillis());
error = true;
}
PLog plog = new PLog(wayPoints.toArray(new WayPoint[wayPoints.size()]));
someThread.addToQueue(plog);//...submit for further processing on separate thread
return true;
}
在第一段代码中,JIT 可以重新排序“someThread.addToQueue()”和“wayPoints.put()”,因为编译器可以判断 wayPoints 不会被进一步读取到当前线程中。但在固定代码中,由于我使用 wayPoints 来构造新的 PLog 实例,我现在是否有效地阻止了 JIT 重新排序?
引用.... http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5
从 JLS 第 17.4.5 节的阅读中,我认为我已经创建了一个具有法律约束力的happens-before,这将阻止重新排序,因为我现在在写入后从 wayPoints 中读取......“如果 x 和y 是同一线程的操作,x 按程序顺序出现在 y 之前,然后是 hb(x, y)。”
谢谢!
最佳答案
您完全正确,您已经创建了发生之前的关系。 一般来说
a = X; ( X 是一些不涉及 a 和 b 的常量或表达式) b=Y; ( Y 是一些不涉及 a 和 b 的常量或表达式)
以上两个可以通过 JIT 重新排序
但是 a = X ; b = a * Y;
不会重新排序。这几乎就是您在更正中所做的事情。
解决问题的其他方法是声明 wayPoints volatile 。如果将 wayPoints 声明为 volatile ,则写入 volatile ( wayPoints) 不会与原始程序顺序中的其他内存操作 ( someThread.addToQueue() ) 重新排序。
关于java - 防止 Java 中的 JIT 重新排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19649588/