这是Core Java第8版第757页的一节
注意:
public void flipDone() {
done = !done;
}
//不是原子
我不明白为什么它不是原子的。谁能告诉我为什么?感谢
答案 0 :(得分:7)
计算机以三个不同的步骤执行flipDone
方法:
Read the value of memory location labeled done into ALU
Flip the value (i.e true -> false or false -> true)
Write the new value into the memory location done
在Java中,可以在多个线程中调用一段代码。应将这些线程视为执行代码并发。
比如说,标记为done
的内存位置最初包含值false
。考虑两个调用flipDone
的线程,产生以下一系列步骤:
Thread 1 Thread 2
-----------------------------------------------------------------------
Read value of done, false
Invert that value to true
Write the new value, true, to done
Read value of done, now true
Invert that value to false
Write the new value, false, to done
flipDone
方法被调用了两次。 done
从false
转到true
,然后又回到false
- 正如人们所料。但由于线程并发执行,因此这不是步骤的唯一顺序。请考虑这个顺序:
Thread 1 Thread 2
-----------------------------------------------------------------------
Read value of done, false
Invert that value to true Read value of done, false
Write the new value, true, to done Invert that value to true
Write the new value, true, to done
当第一个线程反转它读取的值时,第二个线程同时读取该值。类似地,当第一个线程将值写入内存时,第二个线程正在反转值 it read 。 Thread 2
完成后,done
的值将为true。在这里,虽然flipDone
被调用了两次,但done
只翻了一次!其中一个更新似乎已丢失。这是本书试图警告你的问题。
答案 1 :(得分:6)
这里有三个步骤:
done
done
没有什么可以阻止另一个线程在所有这些中间预先占用。
答案 2 :(得分:4)
因为两个线程可能同时调用flipDone()
方法,所以done
变量的状态是不确定的。
答案 3 :(得分:4)
执行时
done = !done;
实际发生的是:
1. Get the value of done
2. Apply the not operator
3. Assign it to done
如果两个线程一起执行第一步,它们将具有相同的完成值,因此它们不会更改两次,而是只更改一次。
例如,如果最初完成为true,则在将其更改两次之后,您会发现它仍然是真的,但如果两个线程一起执行步骤1,则它将为false。
答案 4 :(得分:0)
它不是作为单个不可分割的操作执行,而是三个离散操作的序列 - 获取当前的完成值,取消值,将新值写回完成。这是一个read-modify-write
操作,其结果状态来自先前的状态。