AtomicReference实例使用Unsafe CAS操作来利用处理器指令进行锁定。但是我有点困惑它是如何在复杂对象的情况下工作的。
例如,让我们假设我有一个Person类的实例(id,firstName,lastName)。我正在将对象实例共享给多个线程t1,t2和t3。由于操作应该是原子操作,所以不是共享Person类对象实例,而是将该对象包装到AtomicReference实例中并与所有线程共享。
现在,线程t1仅更新firstName,线程t2仅更新lastName,线程t3更新firstName和lastName。之后,每个线程都会调用compareAndSet方法来反映新的更改。
此外,我使用volatile引用,以便写入可以在主内存中发生并且对所有线程都可见。
我想明白:
在上面调用compareAndSet的场景中,Person类实例的期望值和新值之间要比较的是什么(例如id,firstName,lastName)?
假设线程t1已更新firstName并调用compareAndSet。线程t2更新了lastName,只是调用compareAndSet。在这种情况下,AtomicReference如何保证线程t2不会删除线程t1所做的更改,即更新firstName?
假设2个线程t1和t2同时调用compareAndSet然后谁将赢得比赛以及其他线程会发生什么损失?
答案 0 :(得分:2)
如果您共享了可变Person
个对象,则AtomicReference
根本无法帮助您。每次要应用更改时,都需要使Person
不可变并创建新的Person
。这样,线程更新的字段数无关紧要。所以假设你有这样的不可变Person
类:
public class Person {
public final int id;
public final String firstName, lastName;
public Person(int id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
}
然后您的主题可能会执行以下操作
AtomicReference<Person> ref; // shared reference
public void updateFirstName(String firstName) {
Person curPerson, newPerson;
do {
curPerson = ref.get();
newPerson = new Person(curPerson.id, firstName, curPerson.lastName);
} while (!ref.compareAndSet(curPerson, newPerson));
}
public void updateLastName(String lastName) {
Person curPerson, newPerson;
do {
curPerson = ref.get();
newPerson = new Person(curPerson.id, curPerson.firstName, lastName);
} while (!ref.compareAndSet(curPerson, newPerson));
}
public void updateName(String firstName, String lastName) {
Person curPerson, newPerson;
do {
curPerson = ref.get();
newPerson = new Person(curPerson.id, firstName, lastName);
} while (!ref.compareAndSet(curPerson, newPerson));
}
调用此类方法,您将整体更新Person
,并且不会有任何竞争条件。
至于你的第三个问题,它没有被指定,谁会赢,但是失败的线程只会再做一次迭代并相应地更新另一个字段,所以你最终会更新这两个字段。
答案 1 :(得分:0)
AtomicReference
的重点是代表
可以原子方式更新的对象引用。
它不会阻止您以原子方式修改引用所指向的对象。
在
compareAndSet
被调用的上述场景中,有什么事情 将在Person类的预期值和新值之间进行比较 实例(例如,id,firstName,lastName)?
没有一个。 compareAndSet
将使用引用相等来验证当前引用是否等于expected
引用,即。 ==
。来自javadoc
如果是当前值,则以原子方式将值设置为给定的更新值 值
==
预期值。
它不了解或关心参考文献的类型,因此不了解或关心其成员或您定义它们的逻辑。
假设2个线程t1和t2同时调用
compareAndSet
谁将赢得比赛以及其他失败的线索会发生什么?
订单未定义。 compareAndSet
仅在当前引用等于给定的预期引用时才有效。该方法将返回
true
如果成功。false
返回表示实际值为 不等于预期值。