public abstract class CountedCompleter<T> extends ForkJoinTask<T>
ForkJoinTask
完成动作。countedcompleters一般是在任务档和堵塞的存在比其他形式的forkjointasks更强大,但不太直观的程序。采用countedcompleter是相似的其他竣工部件(如
CompletionHandler
)除了多待完成可能需要触发
onCompletion(CountedCompleter)
完成动作,不只是一个。除非初始化,否则,
pending count的从零开始的,但可能是(原子)的使用方法
setPendingCount(int)
,
addToPendingCount(int)
,和
compareAndSetPendingCount(int, int)
改变。在调用
tryComplete()
未决诉讼,如果计数为零,这是递减的;否则,执行完成的动作,如果完成本身已经完成,过程继续它的完成者。作为与相关同步组件如
Phaser
和
Semaphore
的情况下,这些方法只会影响内部计数;他们没有建立任何进一步的内部簿记。特别是,挂起的任务的身份不被维护。如下图所示,您可以创建一个子类,在需要时记录一些或所有挂起的任务或它们的结果。如下图所示,还提供了实用的方法支持定制完成遍历。然而,因为countedcompleters只提供基本的同步机制,它可以创建子类进一步抽象,保持联系,领域有用,和额外的支持方法适合一组相关的用法。
一个具体的countedcompleter类必须定义方法compute()
,应该在大多数情况下(如下图所示),tryComplete()
一旦调用返回之前。类也可以选择重写方法onCompletion(CountedCompleter)
在正常完成执行的操作和方法onExceptionalCompletion(Throwable, CountedCompleter)
在任何异常动作。
countedcompleters通常不承担结果,在这种情况下,他们通常称为CountedCompleter<Void>
,永远作为一个结果值返回null
。在其他情况下,你应该重写方法getRawResult()
提供从join(), invoke()
结果,和相关的方法。总的来说,这个方法应该返回一个字段的值(或一个或多个字段的功能),将结果完成后的countedcompleter对象。方法setRawResult(T)
默认countedcompleters不起作用。这是可能的,但很少适用,要重写此方法,以保持保持其他对象或字段保持结果数据。
一个countedcompleter,本身并没有一个完整的(即,其中getCompleter()
返回null
)可以被用来作为一个附加功能正常forkjointask。然而,任何完成,则另一者只作为其他计算内部的帮手,所以自己的任务状态(如法如ForkJoinTask.isDone()
报道)是任意的;这种状态的变化只有在complete(T)
,ForkJoinTask.cancel(boolean)
显式调用,ForkJoinTask.completeExceptionally(Throwable)
或在compute
出色的完成方法。在任何特殊的完成,异常可能传递到任务的完成者(及其完善,等等),如果存在有没有已经完成。同样,取消内部countedcompleter对完成只是局部效应,所以不常有用。
示例用法。
并行递归分解。 countedcompleters可布置在树上类似于那些经常使用RecursiveAction
s,虽然参与建立他们通常的结构变化。在这里,每个任务的完成是在计算树的父。尽管他们需要更多一点的记账,countedcompleters可能是更好的选择将可能耗时的操作时(不能进一步细分)对数组或集合中的每个元素;尤其是当操作需要不同的时间来完成一些元素比其他人,或是因为内在的变化(例如我o)或副作用如垃圾收集。因为countedcompleters提供自己的延续,不需要等待其他线程块执行。
例如,这里是一个类的初始版本,使用由两个递归分解划分成一个单一块(叶任务)。即使工作分为个人电话,基于树的技术通常比直接叉叶的任务,因为他们减少线程间的通信,提高负载均衡。在递归的情况下,每一对的第二个任务完成触发其母完成(因为是执行,没有结果相结合的默认无操作实施方法onCompletion
不重写)。一个静态的实用方法设置基本任务和调用它(在这里,隐式地使用ForkJoinPool.commonPool()
)。
class MyOperation<E> { void apply(E e) { ... } }
class ForEach<E> extends CountedCompleter<Void> {
public static <E> void forEach(E[] array, MyOperation<E> op) {
new ForEach<E>(null, array, op, 0, array.length).invoke();
}
final E[] array; final MyOperation<E> op; final int lo, hi;
ForEach(CountedCompleter<?> p, E[] array, MyOperation<E> op, int lo, int hi) {
super(p);
this.array = array; this.op = op; this.lo = lo; this.hi = hi;
}
public void compute() { // version 1
if (hi - lo >= 2) {
int mid = (lo + hi) >>> 1;
setPendingCount(2); // must set pending count before fork
new ForEach(this, array, op, mid, hi).fork(); // right child
new ForEach(this, array, op, lo, mid).fork(); // left child
}
else if (hi > lo)
op.apply(array[lo]);
tryComplete();
}
}
本设计可以注意在递归情况改善,任务无关的任务后分叉,所以可以直接调用它的任务返回之前离开。(这是尾递归去除。模拟),因为在执行任务返回左边的任务(而不是通过调用
tryComplete
)待数设置为:
class ForEach<E> ...
public void compute() { // version 2
if (hi - lo >= 2) {
int mid = (lo + hi) >>> 1;
setPendingCount(1); // only one pending
new ForEach(this, array, op, mid, hi).fork(); // right child
new ForEach(this, array, op, lo, mid).compute(); // direct invoke
}
else {
if (hi > lo)
op.apply(array[lo]);
tryComplete();
}
}
作为进一步改进,注意左边的任务甚至不需要存在。而不是创建一个新的,我们可以重复使用原来的任务,并添加一个待计数每个叉。此外,因为在这棵树上没有任务实现
onCompletion(CountedCompleter)
方法,
tryComplete()
可以用
propagateCompletion()
。
class ForEach<E> ...
public void compute() { // version 3
int l = lo, h = hi;
while (h - l >= 2) {
int mid = (l + h) >>> 1;
addToPendingCount(1);
new ForEach(this, array, op, mid, h).fork(); // right child
h = mid;
}
if (h > l)
op.apply(array[l]);
propagateCompletion();
}
额外的改进的类可能需要预先挂起计数使他们可以建立专业类的构造函数,叶的步骤,细分的说,四,而不是每两个迭代,并采用自适应阈值而不是细分到单元素。
搜索.树countedcompleters可以搜索在一个数据结构的不同部分的值或属性,并报告在AtomicReference
结果尽快找到一个。其他人可以调查结果,以避免不必要的工作。(你可以另外cancel其他任务,但它通常是简单、有效的让他们注意到结果集,那么跳过进一步处理。)说明再次用全分配数组(再次,在实践中,叶的任务几乎总是可以处理多个元素):
class Searcher<E> extends CountedCompleter<E> {
final E[] array; final AtomicReference<E> result; final int lo, hi;
Searcher(CountedCompleter<?> p, E[] array, AtomicReference<E> result, int lo, int hi) {
super(p);
this.array = array; this.result = result; this.lo = lo; this.hi = hi;
}
public E getRawResult() { return result.get(); }
public void compute() { // similar to ForEach version 3
int l = lo, h = hi;
while (result.get() == null && h >= l) {
if (h - l >= 2) {
int mid = (l + h) >>> 1;
addToPendingCount(1);
new Searcher(this, array, result, mid, h).fork();
h = mid;
}
else {
E x = array[l];
if (matches(x) && result.compareAndSet(null, x))
quietlyCompleteRoot(); // root task is now joinable
break;
}
}
tryComplete(); // normally complete whether or not found
}
boolean matches(E e) { ... } // return true if found
public static <E> E search(E[] array) {
return new Searcher<E>(null, array, new AtomicReference<E>(), 0, array.length).invoke();
}
}
在这个例子中,以及在哪些任务没有其他的影响除了compareandset共同作用的结果,后无条件调用
tryComplete
可以条件(
if (result.get() == null) tryComplete();
)因为没有进一步的簿记管理所需完成的任务完成后,根。
记录任务。 countedcompleter任务相结合的多个子任务的结果通常需要获得这些结果的方法onCompletion(CountedCompleter)
。如下面的类说明(执行一个简化的形式在Map减少映射和减少所有类型E
),做到这一点的方法之一在分而治之的设计是每个子任务的记录,它的兄弟姐妹,所以它可以访问的方法onCompletion
。该技术适用于在其中结合左和右的结果并不重要,订单减少;下令减少需要明确的左/右的名称。其他streamlinings在上述例子的变种也可以申请。
class MyMapper<E> { E apply(E v) { ... } }
class MyReducer<E> { E apply(E x, E y) { ... } }
class MapReducer<E> extends CountedCompleter<E> {
final E[] array; final MyMapper<E> mapper;
final MyReducer<E> reducer; final int lo, hi;
MapReducer<E> sibling;
E result;
MapReducer(CountedCompleter<?> p, E[] array, MyMapper<E> mapper,
MyReducer<E> reducer, int lo, int hi) {
super(p);
this.array = array; this.mapper = mapper;
this.reducer = reducer; this.lo = lo; this.hi = hi;
}
public void compute() {
if (hi - lo >= 2) {
int mid = (lo + hi) >>> 1;
MapReducer<E> left = new MapReducer(this, array, mapper, reducer, lo, mid);
MapReducer<E> right = new MapReducer(this, array, mapper, reducer, mid, hi);
left.sibling = right;
right.sibling = left;
setPendingCount(1); // only right is pending
right.fork();
left.compute(); // directly execute left
}
else {
if (hi > lo)
result = mapper.apply(array[lo]);
tryComplete();
}
}
public void onCompletion(CountedCompleter<?> caller) {
if (caller != this) {
MapReducer<E> child = (MapReducer<E>)caller;
MapReducer<E> sib = child.sibling;
if (sib == null || sib.result == null)
result = child.result;
else
result = reducer.apply(child.result, sib.result);
}
}
public E getRawResult() { return result; }
public static <E> E mapReduce(E[] array, MyMapper<E> mapper, MyReducer<E> reducer) {
return new MapReducer<E>(null, array, mapper, reducer,
0, array.length).invoke();
}
}
这里,方法
onCompletion
需要形成共同的许多完成设计相结合的结果。这个回调方式触发每一次任务,在两个不同的上下文中,挂起计数,或变为零:(1)通过任务本身,如果其未决的计数为零,在调用
tryComplete
,或(2)任何其子任务在完成和递减的等待计数为零。争论的
caller
区分例。通常,当对方是
this
,没有必要采取行动。否则,调用方的参数可以使用(通常是通过一个演员)提供一个值(和/或链接到其他值)进行合并。如果正确使用有待统计,发生在
onCompletion
行动(一次)在完成一个任务和子任务。在这种方法中不需要额外的同步,以确保访问此任务或其他已完成任务的字段的线程安全性。
完成遍历。如果使用onCompletion
过程完成是不可行或不方便,你可以使用的方法firstComplete()
和nextComplete()
创建定制的遍历。例如,定义一个mapreducer只打出右侧的任务在第三个例子的形式,完成未尽的任务必须合作减少环节,可以做如下:
class MapReducer<E> extends CountedCompleter<E> { // version 2
final E[] array; final MyMapper<E> mapper;
final MyReducer<E> reducer; final int lo, hi;
MapReducer<E> forks, next; // record subtask forks in list
E result;
MapReducer(CountedCompleter<?> p, E[] array, MyMapper<E> mapper,
MyReducer<E> reducer, int lo, int hi, MapReducer<E> next) {
super(p);
this.array = array; this.mapper = mapper;
this.reducer = reducer; this.lo = lo; this.hi = hi;
this.next = next;
}
public void compute() {
int l = lo, h = hi;
while (h - l >= 2) {
int mid = (l + h) >>> 1;
addToPendingCount(1);
(forks = new MapReducer(this, array, mapper, reducer, mid, h, forks)).fork();
h = mid;
}
if (h > l)
result = mapper.apply(array[l]);
// process completions by reducing along and advancing subtask links
for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
for (MapReducer t = (MapReducer)c, s = t.forks; s != null; s = t.forks = s.next)
t.result = reducer.apply(t.result, s.result);
}
}
public E getRawResult() { return result; }
public static <E> E mapReduce(E[] array, MyMapper<E> mapper, MyReducer<E> reducer) {
return new MapReducer<E>(null, array, mapper, reducer,
0, array.length, null).invoke();
}
}
触发器。一些countedcompleters本身不分叉,而是作为其他设计管道位;包括一个或多个异步任务触发另一个异步任务的完成。例如:
class HeaderBuilder extends CountedCompleter<...> { ... }
class BodyBuilder extends CountedCompleter<...> { ... }
class PacketSender extends CountedCompleter<...> {
PacketSender(...) { super(null, 1); ... } // trigger on second completion
public void compute() { } // never called
public void onCompletion(CountedCompleter<?> caller) { sendPacket(); }
}
// sample use:
PacketSender p = new PacketSender();
new HeaderBuilder(p, ...).fork();
new BodyBuilder(p, ...).fork();
Modifier | Constructor and Description |
---|---|
protected |
CountedCompleter()
创造没有完成和初始挂起计数零的一个新countedcompleter。
|
protected |
CountedCompleter(CountedCompleter<?> completer)
创建具有给定的完成和一个初始挂起计数零的一个新countedcompleter。
|
protected |
CountedCompleter(CountedCompleter<?> completer, int initialPendingCount)
创建具有给定的完成和初始待统计的新countedcompleter。
|
Modifier and Type | Method and Description |
---|---|
void |
addToPendingCount(int delta)
添加(原子)给定值挂起计数。
|
boolean |
compareAndSetPendingCount(int expected, int count)
集(原子)挂起计数的计数只有目前是给定的期望值。
|
void |
complete(T rawResult)
无论在数量,调用
onCompletion(CountedCompleter) ,标志着这项任务完成,进一步引发
tryComplete() 这个任务的完成,如果存在。
|
abstract void |
compute()
此任务执行的主要计算。
|
int |
decrementPendingCountUnlessZero()
如果挂起计数为零,(原子)减少它。
|
protected boolean |
exec()
贯彻执行公约countedcompleters。
|
CountedCompleter<?> |
firstComplete()
如果这个任务的挂起计数为零,返回此任务;否则将其挂起计数并返回
null 。
|
CountedCompleter<?> |
getCompleter()
返回此任务的构造函数建立完成,或
null 如果没有。
|
int |
getPendingCount()
返回当前挂起的计数。
|
T |
getRawResult()
返回计算的结果。
|
CountedCompleter<?> |
getRoot()
返回当前计算的根;即,这个任务没有完成,其他的全是根。
|
void |
helpComplete(int maxTasks)
如果这个任务没有完成,尝试过程最多给其他未处理的任务,这个任务是完成路径数,如果是已知的存在。
|
CountedCompleter<?> |
nextComplete()
如果这个任务没有完成,调用和返回
null
ForkJoinTask.quietlyComplete() 。
|
void |
onCompletion(CountedCompleter<?> caller)
执行一个动作时,方法调用
tryComplete() 待计数为零,或当无条件
complete(T) 调用方法。
|
boolean |
onExceptionalCompletion(Throwable ex, CountedCompleter<?> caller)
执行一个动作时
ForkJoinTask.completeExceptionally(Throwable) 调用方法或方法
compute() 抛出一个异常,这工作已经不能正常完成,否则。
|
void |
propagateCompletion()
相当于
tryComplete() 但不调用
onCompletion(CountedCompleter) 沿完成路径:如果挂起计数为零,递减计数;否则,同样试图完成这一任务的完成,如果存在的话,其他的是这个任务完成。
|
void |
quietlyCompleteRoot()
相当于
getRoot().quietlyComplete() 。
|
void |
setPendingCount(int count)
将挂起的计数设置为给定的值。
|
protected void |
setRawResult(T t)
一,轴承countedcompleters可以用来帮助保持结果数据的方法。
|
void |
tryComplete()
如果挂起计数为零,递减计数;否则调用
onCompletion(CountedCompleter) 然后同样试图完成这一任务的完成,如果存在的话,其他的是这个任务完成。
|
adapt, adapt, adapt, cancel, compareAndSetForkJoinTaskTag, completeExceptionally, fork, get, get, getException, getForkJoinTaskTag, getPool, getQueuedTaskCount, getSurplusQueuedTaskCount, helpQuiesce, inForkJoinPool, invoke, invokeAll, invokeAll, invokeAll, isCancelled, isCompletedAbnormally, isCompletedNormally, isDone, join, peekNextLocalTask, pollNextLocalTask, pollTask, quietlyComplete, quietlyInvoke, quietlyJoin, reinitialize, setForkJoinTaskTag, tryUnfork
protected CountedCompleter(CountedCompleter<?> completer, int initialPendingCount)
completer
-这个任务的完成者,或
null
如果没有
initialPendingCount
-初始挂起计数
protected CountedCompleter(CountedCompleter<?> completer)
completer
-这个任务的完成者,或
null
如果没有
protected CountedCompleter()
public abstract void compute()
public void onCompletion(CountedCompleter<?> caller)
tryComplete()
待计数为零,或当无条件
complete(T)
调用方法。默认情况下,此方法不做任何事。您可以通过检查给定来电者参数的身份来区分情况。如果不等于
this
,那么它是一个典型的任务,可能包含的结果(和/或链接到其他结果)相结合。
caller
-任务调用这个方法(这可能是这个任务本身)
public boolean onExceptionalCompletion(Throwable ex, CountedCompleter<?> caller)
ForkJoinTask.completeExceptionally(Throwable)
调用方法或方法
compute()
抛出一个异常,这工作已经不能正常完成,否则。在进入这个方法,这个任务
ForkJoinTask.isCompletedAbnormally()
。此方法的返回值控制进一步传播:如果
true
这任务已经完成,没有完成,那全是同时完成的异常,这一异常者。此方法的默认实现不返回
true
除外。
ex
-例外
caller
-任务调用这个方法(这可能是这个任务本身)
true
例外应传播这项任务的完成,如果存在
public final CountedCompleter<?> getCompleter()
null
如果没有。
public final int getPendingCount()
public final void setPendingCount(int count)
count
-伯爵
public final void addToPendingCount(int delta)
delta
-价值增加
public final boolean compareAndSetPendingCount(int expected, int count)
expected
-期望值
count
-新价值
true
如果成功
public final int decrementPendingCountUnlessZero()
public final CountedCompleter<?> getRoot()
public final void tryComplete()
onCompletion(CountedCompleter)
然后同样试图完成这一任务的完成,如果存在的话,其他的是这个任务完成。
public final void propagateCompletion()
tryComplete()
但不调用
onCompletion(CountedCompleter)
沿完成路径:如果挂起计数为零,递减计数;否则,同样试图完成这一任务的完成,如果存在的话,其他的是这个任务完成。这种方法可能是有用的情况下
onCompletion
不应该在哪里,或者不需要,被调用每个者在计算。
public void complete(T rawResult)
onCompletion(CountedCompleter)
,标志着这项任务完成,进一步引发
tryComplete()
这个任务的完成,如果存在。给定的rawresult作为参数调用
onCompletion(CountedCompleter)
setRawResult(T)
或标记这个任务完成之前;它的价值才有意义
setRawResult
类重写。此方法不修改挂起的计数。
这种方法可能是有用的当强迫完成只要一有人(而不是所有)的几个子任务的结果。然而,在共同的(推荐)的案件中,setRawResult
不重写,这种效果可以更简单地使用quietlyCompleteRoot();
获得。
complete
方法重写,继承类
ForkJoinTask<T>
rawResult
-原结果
public final CountedCompleter<?> firstComplete()
null
。这种方法是设计用于完成遍历循环
nextComplete()
。
null
public final CountedCompleter<?> nextComplete()
null
ForkJoinTask.quietlyComplete()
。或者,如果完整的申请数非零,减少待计数并返回
null
。否则,返回去。这种方法可以作为一个同质的任务层次完成遍历循环部分:
for (CountedCompleter<?> c = firstComplete();
c != null;
c = c.nextComplete()) {
// ... process c ...
}
null
public final void quietlyCompleteRoot()
getRoot().quietlyComplete()
。
public final void helpComplete(int maxTasks)
maxTasks
-任务的最大数目的过程。如果小于或等于零,则没有处理任务。
protected final boolean exec()
exec
方法重写,继承类
ForkJoinTask<T>
true
如果这个任务已经完成正常
public T getRawResult()
null
,这是适当的
Void
行动,但在其他情况下,需要重写,几乎总是返回一个字段或函数的一个字段保存结果完成后。
getRawResult
方法重写,继承类
ForkJoinTask<T>
protected void setRawResult(T t)
setRawResult
方法重写,继承类
ForkJoinTask<T>
t
-价值
Submit a bug or feature
For further API reference and developer documentation, see Java SE Documentation. That documentation contains more detailed, developer-targeted descriptions, with conceptual overviews, definitions of terms, workarounds, and working code examples.
Copyright © 1993, 2014, Oracle and/or its affiliates. All rights reserved.