这是两个原子操作:
int value = 5;
Object obj = new Object();
但是当使用原语作为方法参数时,这会被视为原子操作:
public void setValue(int val, Object obj){
this.value = val; // Atomic?
this.obj = obj; // Not atomic?
}
? 对象引用的副本不是原子的,因为它包含一个read和write,对吗?
说对象引用进行原子操作的唯一方法是将其声明为null或为其分配新对象,如:
是否正确?Object obj = null;
和
Object obj = new Object();
答案 0 :(得分:4)
如果上述方法中的参数是对象的引用, 然后操作不会是原子的,对吧?
一般来说,这是正确的。一个好的经验法则是考虑根本没有原子性,即使是像以下原语:
int b,c;
int a = ++b - c;
只有原语,但整个分配可能不是原子的。
如果您需要原子操作,那么您有不同的可能性:
答案 1 :(得分:3)
当一个线程读取一个原语(long和double除外)或一个对象引用的值时,它会看到它在这个变量中设置的值,或者另一个线程在这个变量中设置的值。
但是,虽然在一个线程中为共享变量赋值是原子的,但这并不意味着所有其他线程都会立即看到新值。为此,应将变量声明为volatile。 volatile也会写入长双原子。在这种情况下,我更喜欢使用AtomicXxx(AtomicLong,AtomicBoolean等)。
如果你想原子地改变两个共享变量的值,那么你应该使用一个独特的锁同步每个访问(读和写)这些变量。
此外,每个“check then act”或“read then write”操作都是非原子的。这意味着这些操作也需要同步:
a++; // read a, increment value, write value to a
if (a > 0) {a = b;} // check value of a, then assign new value to a.
你问题中的每一个操作都是原子的。但是在setValue()
中,你有两个原子操作。整个setValue
调用不是原子的。
答案 2 :(得分:1)
当线程使用变量的值时,它获得的值实际上是由该线程或某个其他线程存储到变量中的值。即使程序不包含正确同步的代码,也是如此。例如,如果两个线程将对不同对象的引用存储到同一个引用值中,则该变量随后将包含对一个对象或另一个对象的引用,而不是对某个其他对象的引用或损坏的引用值。
所以赋值是原子的。
答案 3 :(得分:0)
public synchronized void setValue(int val, Object obj)
现在整个函数都是“原子”,我在Java中没有看到这个术语