来自 OCP Java SE 6 Programmer Practice Exams 的第 291 页,问题 25:
public class Stone implements Runnable {
static int id = 1;
public void run() {
id = 1 - id;
if (id == 0)
pick();
else
release();
}
private static synchronized void pick() {
System.out.print("P ");
System.out.print("Q ");
}
private synchronized void release() {
System.out.print("R ");
System.out.print("S ");
}
public static void main(String[] args) {
Stone st = new Stone();
new Thread(st).start();
new Thread(st).start();
}
}
答案之一是:
The output could be
P Q P Q
我将此答案标记为正确。我的推理:
- 我们正在启动两个线程。
- 第一个进入
run()
。 - 根据JLS 15.26.1 ,它首先评估
1 - id
。结果是0
。它存储在线程的堆栈中。我们正要将该0
保存为静态id
,但是... - Boom,调度程序选择了第二个线程来运行。
- 所以,第二个线程进入
run()
。静态的id
还是1
,所以他执行方法pick()
。P Q
被打印出来。 - 调度器选择第一个线程来运行。它从堆栈中取出
0
并保存到静态id
。因此,第一个线程也执行pick()
并打印P Q
。
但是,书中写到这个答案是不正确的:
It is incorrect because the line
id = 1 - id
swaps the value ofid
between0
and1
. There is no chance for the same method to be executed twice.
我不同意。我认为我上面介绍的场景有一些机会。这种交换不是原子的。我错了吗?
最佳答案
Am I wrong?
不,你是绝对正确的 - 就像你的示例时间线一样。
除了它不是原子的之外,不保证写入 id
无论如何都会被其他线程拾取,因为没有同步并且该字段不是 volatile 的。
这样的引用资料不正确有点令人不安:(
关于java - id = 1 - id 是原子的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27089196/