我正在阅读CountedCompleter
JDK9中的源代码,这是与我的问题相关的代码:
public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
/** The number of pending tasks until completion */
volatile int pending;
// VarHandle mechanics
private static final VarHandle PENDING;
static {
try {
MethodHandles.Lookup l = MethodHandles.lookup();
PENDING = l.findVarHandle(CountedCompleter.class, "pending", int.class);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
/**
* Sets the pending count to the given value.
*
* @param count the count
*/
public final void setPendingCount(int count) {
pending = count;
}
/**
* Adds (atomically) the given value to the pending count.
*
* @param delta the value to add
*/
public final void addToPendingCount(int delta) {
PENDING.getAndAdd(this, delta);
}
/**
* If the pending count is nonzero, (atomically) decrements it.
*
* @return the initial (undecremented) pending count holding on entry
* to this method
*/
public final int decrementPendingCountUnlessZero() {
int c;
do {} while ((c = pending) != 0 &&
!PENDING.weakCompareAndSet(this, c, c - 1));
return c;
}
}
这是我的问题:
PENDING
?为什么不只使用类似的东西AtomicInteger
?setPendingCount()
,但有时使用PENDING
,例如在addToPendingCount()
。它甚至使用了两者,例如decrementPendingCountUnlessZero()
为什么使用挂起和挂起?
前者是场,后者是它的句柄,用于对场执行原子操作。
为什么不只使用AtomicInteger之类的东西呢?
他们可以。我怀疑这只是表演。并发API的大多数部分都经过了高度优化,因为它们很可能涉及紧密循环。
AtomicInteger
在底层执行与确保原子操作基本相同的操作,因此使用它将是方法调用的一种间接级别,仅使用少量复制粘贴即可实现此目的。是的,性能提升绝对是很小的,但是对于某些专业应用程序来说,这将是值得的。
是的,重用代码会更简洁AtomicInteger
,但是并发API中的目标与您或我的项目的目标不同。性能是第一要务,其他都是次要的。
为什么有时使用
pending
,例如在中setPendingCount()
,但有时使用PENDING
它直接将volatile字段用于已经是原子的操作。setPendingCount
只是分配给领域
public final void setPendingCount(int count) {
pending = count;
}
其他需要比较和设置的情况需要充当原子操作,并VarHandle
提供该功能
public final boolean compareAndSetPendingCount(int expected, int count) {
return PENDING.compareAndSet(this, expected, count);
}
它甚至使用了两者,例如
decrementPendingCountUnlessZero()
同样,答案是原子性。他们用这种方法编写的方式是实现该功能原子性的最高效方式。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句