AtomicReference.compareAndSet()用于确定什么?

说你有以下课程

public class AccessStatistics { private final int noPages, noErrors; public AccessStatistics(int noPages, int noErrors) { this.noPages = noPages; this.noErrors = noErrors; } public int getNoPages() { return noPages; } public int getNoErrors() { return noErrors; } } 

并执行以下代码

 private AtomicReference stats = new AtomicReference(new AccessStatistics(0, 0)); public void incrementPageCount(boolean wasError) { AccessStatistics prev, newValue; do { prev = stats.get(); int noPages = prev.getNoPages() + 1; int noErrors = prev.getNoErrors; if (wasError) { noErrors++; } newValue = new AccessStatistics(noPages, noErrors); } while (!stats.compareAndSet(prev, newValue)); } 

在最后一行while (!stats.compareAndSet(prev, newValue)) compareAndSet方法如何确定 prevnewValue之间的相等性? 是否需要AccessStatistics类来实现equals()方法? 如果没有,为什么? javadoc为AtomicReference.compareAndSet声明了以下内容

如果当前值==期望值,则以primefaces方式将值设置为给定的更新值。

…但是这个断言似乎非常通用,我在AtomicReference上阅读的教程从未建议为包含在AtomicReference中的类实现equals()。

如果包含在AtomicReference中的类需要实现equals(),那么对于比AccessStatistics更复杂的对象,我认为同步更新对象而不使用AtomicReference的方法可能会更快。

它将refrerence与您使用==运算符完全相同。 这意味着引用必须指向同一个实例。 不使用Object.equals()。

实际上,它没有比较prev和newValue!

相反,它将stats中存储的值与prev进行比较,并且只有当它们相同时,才会将stats中存储的值更新为newValue。 如上所述,它使用equals运算符(==)来执行此操作。 这意味着,当prev指向与stats中存储的同一对象时,将更新统计数据。

它只是检查对象引用相等(aka ==),因此如果获得引用后AtomicReference持有的对象引用已经改变,它将不会更改引用,因此您必须重新开始。

以下是AtomicReference的一些源代码。 AtomicReference指的是对象引用。 此引用是AtomicReference实例中的volatile成员变量,如下所示。

 private volatile V value; 

get()只返回变量的最新值(就像挥发物在“之前发生”方式中所做的那样)。

 public final V get() 

以下是AtomicReference最重要的方法。

 public final boolean compareAndSet(V expect, V update) { return unsafe.compareAndSwapObject(this, valueOffset, expect, update); } 

compareAndSet(expect,update)方法调用Java的不安全类的compareAndSwapObject()方法。 此方法调用unsafe调用本机调用,该调用向处理器调用单个指令。 “期望”和“更新”每个引用一个对象。

当且仅当AtomicReference实例成员变量“value”引用相同的对象时,才引用“expect”,现在将“update”赋给此实例变量,并返回“true”。 否则,返回false。 整个事情都是以primefaces方式完成的。 没有其他线程可以拦截。 由于这是一个单处理器操作(现代计算机体系结构的神奇之处),它通常比使用同步块更快。 但请记住,当需要以primefaces方式更新多个变量时,AtomicReference将无济于事。

我想添加一个完整的运行代码,可以在eclipse中运行。 这将清除许多混乱。 这里有22个用户(MyTh线程)试图预订20个席位。 以下是完整代码后面的代码段。

代码片段,22位用户试图预订20个席位。

 for (int i = 0; i < 20; i++) {// 20 seats seats.add(new AtomicReference()); } Thread[] ths = new Thread[22];// 22 users for (int i = 0; i < ths.length; i++) { ths[i] = new MyTh(seats, i); ths[i].start(); } 

以下是github链接,供那些想要查看小而简洁的运行完整代码的人使用。 https://github.com/sankar4git/atomicReference/blob/master/Solution.java