"private static final VarHandle PENDING" 在 CountedCompleter class 中的作用是什么
What's the effect of "private static final VarHandle PENDING" in CountedCompleter class
我正在阅读JDK9中CountedCompleter
的源代码,这里是与我的问题相关的代码:
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 和
PENDING
?为什么不直接使用 AtomicInteger
?
- 为什么有时候用pending,比如
setPendingCount()
,有时候用PENDING
,比如addToPendingCount()
。它甚至同时使用两者,例如 decrementPendingCountUnlessZero()
Why it uses pending and PENDING?
前者是字段,后者是字段的句柄,对字段进行原子操作。
why not just use something like AtomicInteger?
他们可以。我怀疑这只是性能问题。并发性的大部分 API 都进行了高度优化,因为它们很可能涉及紧密循环。
AtomicInteger
在幕后所做的事情与此处所做的基本相同,以确保原子操作,因此使用它将是方法调用的一个间接级别,仅需少量复制粘贴即可.绝对微小的性能提升,是的,但对于一些专门的应用程序来说,这是值得的。
是的,重用 AtomicInteger
会是更简洁的代码,但并发 API 的目标与您或我的项目的目标不同。性能是第一位的,其他都是次要的。
Why sometimes it uses pending
, for example in setPendingCount()
,
but sometimes it uses 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);
}
And it even uses both, for example in
decrementPendingCountUnlessZero()
同样,答案是原子性。他们用这种方法编写它的方式是实现该函数原子性的最有效方式。
我正在阅读JDK9中CountedCompleter
的源代码,这里是与我的问题相关的代码:
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 和
PENDING
?为什么不直接使用AtomicInteger
? - 为什么有时候用pending,比如
setPendingCount()
,有时候用PENDING
,比如addToPendingCount()
。它甚至同时使用两者,例如decrementPendingCountUnlessZero()
Why it uses pending and PENDING?
前者是字段,后者是字段的句柄,对字段进行原子操作。
why not just use something like AtomicInteger?
他们可以。我怀疑这只是性能问题。并发性的大部分 API 都进行了高度优化,因为它们很可能涉及紧密循环。
AtomicInteger
在幕后所做的事情与此处所做的基本相同,以确保原子操作,因此使用它将是方法调用的一个间接级别,仅需少量复制粘贴即可.绝对微小的性能提升,是的,但对于一些专门的应用程序来说,这是值得的。
是的,重用 AtomicInteger
会是更简洁的代码,但并发 API 的目标与您或我的项目的目标不同。性能是第一位的,其他都是次要的。
Why sometimes it uses
pending
, for example insetPendingCount()
, but sometimes it usesPENDING
它直接对已经是原子的操作使用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);
}
And it even uses both, for example in
decrementPendingCountUnlessZero()
同样,答案是原子性。他们用这种方法编写它的方式是实现该函数原子性的最有效方式。