【发布时间】:2013-09-21 06:06:10
【问题描述】:
在某些链接中给出了同步块内的代码重新排序是可能的,而其他一些站点则说不可能。你能举个例子来描述一下使用同步时代码重新排序的实际情况吗?
【问题讨论】:
标签: java multithreading jvm synchronized java-memory-model
在某些链接中给出了同步块内的代码重新排序是可能的,而其他一些站点则说不可能。你能举个例子来描述一下使用同步时代码重新排序的实际情况吗?
【问题讨论】:
标签: java multithreading jvm synchronized java-memory-model
有两种可能的重新排序:
但更重要的是:如果您的代码正确同步,这些重新排序不会影响程序的执行,这是您应该关心的全部。
示例(所有变量最初为 0):
线程1:
a=1;
synchronized(lock) {
b=1;
c=1;
}
d=1;
线程2:
synchronized(lock) {
if (a==1) print(b); // can print 0 or 1
if (b==1) print(a)/print(c); // always prints 1
if (b==1) print(d); // can print 0 or 1
if (d==1) print(a)/print(b)/print(c); // always prints 1
}
特别是,允许将 d=1 移动到 c=1 之前或将 a=1 移动到 b=1 之后,因为线程 2 无法观察到,因为线程 1 执行的同步块看起来就像来自线程 2 的原子操作。
另一方面,不使用相同锁的线程将能够观察到这些重新排序。
【讨论】:
运行时可能会重新排序操作,只要尊重发生之前。规范writes:
应该注意的是,两个动作之间存在发生之前的关系并不一定意味着它们必须在实现中以该顺序发生。如果重新排序产生与合法执行一致的结果,则不是非法的。
和
更具体地说,如果两个操作共享一个happens-before 关系,那么对于它们不共享happens-before 关系的任何代码,它们不一定必须以该顺序发生。例如,一个线程中的写入与另一个线程中的读取处于数据竞争中,这些读取可能会出现乱序。
特别是,如果一个线程这样做:
synchronized (lock) {
x = 1;
y = 1;
}
还有一个:
if (y == 1) System.out.println(x);
这些线程之间没有happens-before关系,另一个线程可能会观察到y在x之前被分配,并打印0。
【讨论】: