AtkyReference如何在复杂对象

时间:2015-10-14 03:24:48

标签: java multithreading atomicreference

AtomicReference实例使用Unsafe 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然后谁将赢得比赛以及其他线程会发生什么损失?

2 个答案:

答案 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返回表示实际值为   不等于预期值。