-1

AtomicReference 实例使用不安全的 CAS 操作来利用处理器指令进行锁定。但是我有点困惑它在复杂对象的情况下是如何工作的。

例如,假设我有一个 Person 类的实例(id、firstName、lastName)。我将对象实例共享给多个线程 t1、t2 和 t3。由于操作应该是原子的,所以我不会共享 Person 类对象实例,而是将该对象包装到 AtomicReference 实例中并与所有线程共享。

现在线程 t1 只更新 firstName,线程 t2 只更新 lastName,线程 t3 更新 firstName 和 lastName。之后,每个线程都会调用 compareAndSet 方法来反映新的变化。

此外,我正在使用 volatile 引用,以便写入可以发生在主内存中并且对所有线程可见。

我想了解:

  1. 在上述情况下,当 compareAndSet 被调用时,Person 类实例的预期值和新值之间会比较哪些内容(例如 id、firstName、lastName)?

  2. 假设线程 t1 更新了 firstName 并调用了 compareAndSet。线程 t2 更新了 lastName 并且将调用 compareAndSet。在这种情况下,AtomicReference 如何保证线程 t2 不会删除线程 t1 所做的更改,即更新 firstName?

  3. 假设 2 个线程 t1 和 t2 同时调用 compareAndSet,那么谁会赢得比赛,而其他输了的线程会发生什么?

4

2 回答 2

5

如果您有共享可变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整体更新,并且不会有任何竞争条件。

至于你的第三个问题,没有指定谁会赢,但是失败的线程只会再进行一次迭代并相应地更新另一个字段,所以你最终会更新这两个字段。

于 2015-10-14T03:36:10.353 回答
0

an 的全部意义AtomicReference在于表示

可以自动更新的对象引用。

它不会阻止您以原子方式修改引用指向的对象。

在上述情况下,当compareAndSet被调用时,Person 类实例的预期值和新值之间会比较哪些内容(例如 id、firstName、lastName)?

这些都没有。compareAndSet将使用引用相等来验证当前引用是否等于expected引用,即。==. 来自 javadoc

如果当前值==是预期值,则以原子方式将该值设置为给定的更新值。

它不知道也不关心引用的类型,因此不知道也不关心它的成员或定义它们的逻辑。

假设 2 个线程 t1 和 t2compareAndSet同时调用,那么谁会赢得比赛,而其他输了的线程会发生什么?

订单未定义。compareAndSet仅当当前参考等于给定的预期参考时才会起作用。该方法将返回

true如果成功。falsereturn 表示实际值不等于期望值。

于 2015-10-14T03:31:59.033 回答