当我想知道这个问题时,我在设计的应用程序中担心竞争条件.
假设我有一个大型数组或某种类型的集合,由我的程序的一个组件管理,让我们称之为组件Monitor.它的工作是定期检查集合是否"脏",即最近是否已更改,如果是,则将快照写入磁盘(这是为了在发生崩溃时检查应用程序)并再次将其标记为干净.
在不同线程中运行的同一程序的其他组件调用Monitor的方法来向数组/集合中添加数据或修改数据.这些方法将集合标记为脏.
现在,改变方法在其他组件的线程中运行,对吧?如果我不是那么幸运,可以在快照写入磁盘时调用它们,更改已经写入的数据,设置脏标志,监视器的线程在此之后取消设置,而不保存更改(它当它改变时已经超过了元素).所以我有一个标记为干净的脏集合.
有一段时间,我认为我可以通过制作集合的临时副本来解决问题,将其标记为干净,然后再序列化副本.但复制是否是原子的,即我可以确定在复制时集合不会改变吗?
与此同时,我认为我找到了更好的解决方案
在开始写入磁盘之前设置锁定标志,并使数据更改方法等待,直到取消设置该标志
让数据更改方法写入"更改队列"而不是直接写入集合,并让具有磁盘写入进程的线程队列
我认为锁定标志可能是最好的方式.但我仍然好奇:复制变量原子?
后续行动:也许这应该是一个自己的问题,但实际上它是非常相同的.根据下面的答案,我的"锁定旗帜"方法可能也行不通,对吧?因为数据更改方法可能会在将锁定标志设置为"锁定"值时检查锁定标志并确定它未锁定.所以我需要一个像mutex这样的特殊结构,如果我真的想做到这一点,对吗?
荣誉对埃里克森对他非常有帮助的答案在我的跟进.我真的应该提出这两个问题,所以我可以接受两个答案.拜托,也请他投票.
不可以.例如,Java中的长变量在32位机器上不是原子的.
此外,还存在"线程缓存"问题 - 除非您的变量是易失性或在同步块内,否则另一个线程可能看不到变量值的变化.对于所有类型的变量都是如此,而不仅仅是长期变量.
请阅读此处:http://gee.cs.oswego.edu/dl/cpj/jmm.html,尤其是"原子性"和"可见性"段落.
不,这不是原子的. 请参阅此问题,了解为何以及如何处理该问题.