假设你有以下课程
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<AccessStatistics> stats =
new AtomicReference<AccessStatistics>(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
方法 如何确定prev
和newValue
之间的平等 ?实现AccessStatistics
方法需要equals()
类吗?如果没有,为什么? javadoc为AtomicReference.compareAndSet
如果当前值==预期值,则以原子方式将值设置为给定的更新值。
...但是这个断言似乎非常通用,我在AtomicReference上阅读的教程从未建议为包含在AtomicReference中的类实现equals()。
如果需要在AtomicReference中包装的类实现equals(),那么对于比AccessStatistics
更复杂的对象,我认为同步更新对象而不使用AtomicReference的方法可能会更快。
答案 0 :(得分:4)
它完全比较了使用==运算符的refrerence。这意味着引用必须指向同一个实例。没有使用Object.equals()。
答案 1 :(得分:2)
实际上,不比较prev和newValue!
相反,它将stats中存储的值与prev进行比较,只有当它们相同时,才会将stats中存储的值更新为newValue。如上所述,它使用equals运算符(==)来执行此操作。这意味着当prev指向与统计数据中存储的同一对象时,将更新统计数据。
答案 2 :(得分:0)
它只是检查对象引用相等(aka ==),因此如果获得引用后AtomicReference持有的对象引用已经更改,它将不会更改引用,因此您必须重新开始。
答案 3 :(得分:0)
以下是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。整个事情都是以原子方式完成的。没有其他线程可以拦截。由于这是单处理器操作(现代计算机体系结构的神奇之处),它通常比使用同步块更快。但请记住,当需要以原子方式更新多个变量时,AtomicReference将无济于事。
我想添加一个完整的运行代码,可以在eclipse中运行。这将清除许多混乱。这里有22个用户(MyTh线程)试图预订20个席位。以下是完整代码后面的代码段。
代码段,其中22位用户试图预订20个席位。
for (int i = 0; i < 20; i++) {// 20 seats
seats.add(new AtomicReference<Integer>());
}
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