赋值和函数值计算是原子操作吗?

时间:2011-08-02 21:50:52

标签: java multithreading variable-assignment atomic

我想知道函数值的计算和结果对变量的赋值是否是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分配不正确的值。

非常感谢官方文献的链接。

感谢。

4 个答案:

答案 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)

函数值的计算不可能是原子的。该函数可以在返回值之前运行多年。