我想知道函数值的计算和结果对变量的赋值是否是Java中的原子操作。
例如:
我有一个线程安全的优先级队列q
。在q
中我保存了元素,每个元素都有一个rank
,根据它放在队列中。另外,我有一个共享变量topRank
,它应该始终包含q
中最顶层元素的等级。以下代码由线程数并行执行:
element = q.remove(); // do something with element
topRank = q.peek();
可能会发生threadA会从q
中删除一个元素并计算q.peek()
的值,并且在将其分配给topRank
之前会被threadB中断,然后threadB会再删除一个元素来自q
并更新topRank
的元素。然后threadA将继续为topRank
分配不正确的值。
非常感谢官方文献的链接。
感谢。
答案 0 :(得分:4)
简短的回答是这些操作不是原子操作,您需要将同步写入代码中。这是一个巨大的主题,有很多关于编写线程安全程序的知识。谷歌为“java线程安全”和“java多线程”。
答案 1 :(得分:1)
线程安全仅指 remove()
或peek()
次调用中的操作。除非你采取措施阻止线程相互竞争,否则完全有可能与topRank
比赛。
有关详细信息,请查看Java synchronization tutorial。
答案 2 :(得分:0)
1)我不认为存在原子操作,除非你保护它们(同步和其他技术)。
2)那就是说,它不适用于你的例子。
在你的例子中,你有。
a)致电q.remove()
b)q.remove()
完成其工作(线程安全与否)。
c)q.remove()
返回结果
d)结果被分配给element
(这是作业!!所有以前只是计算要分配的值。)
因此,不仅要求赋值(操作的最后一步)是原子的,还需要确保q.remove()也是原子的。而且我向你保证,事实并非如此。
由于它不是线程安全的,如果你想避免并发访问,你应该同步整个块。
EDIT回答了作者的评论。
所以你要问的是,如果某种方式q.peek()
将返回一个元素,而另一个将以topRank
结束,因为其他线程搞乱它,不是吗?
除非topRank
由不同的线程共享,否则不可能:
a)q.peek()
运行其逻辑
b)复制q.peek()
的返回值(存储在堆栈中,返回到调用q.peek()
的表达式)
c)q.peek()
退出。只有现在其他实例才能访问synchronized部分来更改q.state,但返回值已经复制到堆栈中。
d)堆栈中的副本被分配到topRank
答案 3 :(得分:0)
函数值的计算不可能是原子的。该函数可以在返回值之前运行多年。