AtomicReference如何使用CAS来处理复杂对象

问题描述:

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

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

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

此外,我正在使用易失性参考,以便写入可以发生在主内存和所有线程都可见。

我想明白了:

  1. 在上述情况下,当compareAndSet被调用,有什么期望之间将被比较的东西和新的价值Person类的实例(如ID,名字,姓氏)?

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

  3. 假设2个线程t1和t2同时调用了compareAndSet那么谁将赢得比赛以及其他线程谁会失败呢?

一个AtomicReference整点是代表

可以用原子方式更新的对象引用。

它没有阻止你自动修改引用指向的对象。

在,什么是Person类 实例(例如ID,名字,姓氏)的事情 预期之间将进行比较和新的价值上面的场景时compareAndSet被调用?

没有那些。 compareAndSet将使用引用相等来验证当前引用等于expected引用,即。 ==。根据JavaDoc

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

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

假设2个线程T1和T2称为compareAndSet在同一时间,然后 谁就能赢得比赛,会发生什么其他的线程谁的损失?

订单未定义。 compareAndSet只在当前参考值等于给定预期参考值时才有效。该方法将返回

true如果成功。 false return表示实际值为 不等于预期值。

如果您有共享的可变对象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作为一个整体,不会有任何竞争条件。

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