是什么AtomicReference.compareAndSet()使用的决心?
-
18-09-2019 - |
题
假设你有下面的类
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更加复杂。
解决方案
有完全一样,如果您使用了==运算符的refrerences进行比较。这意味着,引用必须指向同一个实例。的Object.Equals()不被使用。
其他提示
其实,它的不的比较上一个和NEWVALUE!
相反,它存储的统计信息内PREV并且仅当那些是相同的,它更新存储到NEWVALUE统计内的值的值进行比较。正如上面所说的,它使用等号运算符(==)这样做。这意味着,当ANLY先前所指向的相同的对象被存储在统计信息的统计信息将被更新。
这只是检查对象引用相等(又名==),因此,如果通过的AtomicReference持有对象引用改变了你得到了引用后,它不会改变的参考,所以你必须重新开始。
以下是一些的AtomicReference的源代码的。的AtomicReference是指一个对象引用。此引用中,如下所示的AtomicReference实例挥发性成员变量。
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(期望的那样,更新)方法调用不安全类的Java的compareAndSwapObject()方法。此方法不安全的呼叫调用本机呼叫,这将调用单个指令到处理器。 “期望”和“更新”每一个参考对象。
如果且仅当的AtomicReference实例成员变量“值”指的是相同的目的是通过“期望”,“更新”现在被分配给该实例变量,和“真”返回参照。否则,返回false。整个事情是自动完成的。没有其他线程可以拦截之间。由于这是一个单处理器操作(现代计算机体系结构的魔法),它往往比使用同步块更快。但请记住,当多个变量需要用原子方式更新,的AtomicReference也无济于事。
我想补充完全成熟的运行代码,它可以在蚀运行。这将明确很多混乱。这里22用户(神话线程)正在尝试预订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