CountedCompleter 類別
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
, ForkJoinTask
具有在觸發時執行的完成動作,而且沒有剩餘的擱置動作。
[Android.Runtime.Register("java/util/concurrent/CountedCompleter", ApiSince=24, DoNotGenerateAcw=true)]
[Java.Interop.JavaTypeParameters(new System.String[] { "T" })]
public abstract class CountedCompleter : Java.Util.Concurrent.ForkJoinTask
[<Android.Runtime.Register("java/util/concurrent/CountedCompleter", ApiSince=24, DoNotGenerateAcw=true)>]
[<Java.Interop.JavaTypeParameters(new System.String[] { "T" })>]
type CountedCompleter = class
inherit ForkJoinTask
- 繼承
- 屬性
備註
, ForkJoinTask
具有在觸發時執行的完成動作,而且沒有剩餘的擱置動作。 CountedCompleters 在子任務攤位和封鎖的存在下,通常更強固,而不是其他類型的 ForkJoinTasks,但對程序來說不太直覺。 CountedCompleter 的使用方式與其他完成型元件 (例如) java.nio.channels.CompletionHandler
類似,不同之處在於可能需要多個 <em pending</em>> 完成來觸發完成動作#onCompletion(CountedCompleter)
,而不只是一個。 除非初始化否則,否則 #getPendingCount 擱置計數會從零開始,但可以使用 方法 #setPendingCount
、 #addToPendingCount
和 #compareAndSetPendingCount
來變更 (不可部分完成的)。 在叫 #tryComplete
用 時,如果暫止的動作計數為非零,則會遞減;否則會執行完成動作,而且如果此完成程式本身有完成項,程式就會繼續完成其完成項。 和 等Phaser
Semaphore
相關同步處理元件的情況相同,這些方法只會影響內部計數;它們不會建立任何進一步的內部記帳。 特別是,不會維護暫止工作的身分識別。 如下所示,您可以建立子類別,以在需要時記錄部分或所有暫止的工作或其結果。 如下所示,也提供支援自定義完成周遊的公用程式方法。 不過,因為 CountedCompleters 只提供基本的同步處理機制,所以建立進一步的抽象子類別可能會很有用,以維護連結、字段和其他適用於一組相關使用方式的其他支援方法。
具象的 CountedCompleter 類別必須定義方法 #compute
,在大部分情況下(如下圖所示), tryComplete()
在傳回之前叫用一次。 類別也可以選擇性地覆寫方法 #onCompletion(CountedCompleter)
,以在正常完成時執行動作,以及在任何例外狀況上執行動作的方法 #onExceptionalCompletion(Throwable, CountedCompleter)
。
CountedCompleters 最常不會承擔結果,在此情況下,它們通常會宣告為 CountedCompleter<Void>
,而且一律會以結果值傳回 null
。 在其他情況下,您應該覆寫 方法 #getRawResult
,以提供 來自 join(), invoke()
和 相關方法的結果。 一般而言,這個方法應該會傳回 CountedCompleter 物件在完成時保留結果的欄位值(或一或多個字段的函式)。 方法 #setRawResult
預設不會在 CountedCompleters 中扮演任何角色。 可以,但很少適用,覆寫此方法以維護其他物件或字段保存結果數據。
沒有完整函式的 CountedCompleter(也就是會 #getCompleter
傳回 null
的一個 )可以做為一般 ForkJoinTask,並加入此功能。 不過,任何完成者反過來又有另一個完成者只能做為其他計算的內部協助程式,因此它自己的工作狀態(如 等ForkJoinTask#isDone
方法所報告)是任意的;此狀態只會在明確調用 #complete
、 ForkJoinTask#cancel
ForkJoinTask#completeExceptionally(Throwable)
或 特殊完成方法compute
時變更。 在任何例外完成時,如果存在例外狀況,則例外狀況可能會轉送至工作的完成者(及其完成者等等),否則尚未完成。 同樣地,取消內部 CountedCompleter 只會對完成者產生本機影響,因此通常並不實用。
<b>範例使用方式。</b>
<b>平行遞歸分解。</b> CountedCompleters 可以排列在樹狀結構中,類似於通常與 s 一起使用 RecursiveAction
的樹狀結構,雖然設定它們的建構通常會有所不同。 在這裡,每個工作的完成者是計算樹狀結構中的父代。 即使它們需要更多的記帳,CountedCompleters 在套用可能耗時的作業(無法進一步細分)到陣列或集合的每個元素時,可能比較好的選擇:特別是當作業針對某些元素完成的時間比其他元素要花很多時間時,可能是因為內部變化(例如 I/O)或垃圾收集等輔助效果。 因為 CountedCompleters 提供自己的接續,因此其他工作不需要封鎖等候執行它們。
例如,以下是使用除以二遞歸分解將工作分割成單一片段(分葉工作)之公用程式方法的初始版本。 即使工作分成個別呼叫,樹狀結構型技術通常更適合直接分叉分葉工作,因為它們會減少線程間通訊並改善負載平衡。 在遞歸案例中,每對子工作的第二個完成觸發程式完成其父項(因為不會執行任何結果組合,所以不會覆寫方法 onCompletion
的預設 no-op 實作)。 公用程式方法會設定根工作並叫用它(在這裡,隱含使用 ForkJoinPool#commonPool()
)。 一律將暫止計數設定為子工作數目,並在傳回之前立即呼叫 tryComplete()
,這是直接且可靠的(但並非最佳)。
{@code
public static <E> void forEach(E[] array, Consumer<E> action) {
class Task extends CountedCompleter<Void> {
final int lo, hi;
Task(Task parent, int lo, int hi) {
super(parent); this.lo = lo; this.hi = hi;
}
public void compute() {
if (hi - lo >= 2) {
int mid = (lo + hi) >>> 1;
// must set pending count before fork
setPendingCount(2);
new Task(this, mid, hi).fork(); // right child
new Task(this, lo, mid).fork(); // left child
}
else if (hi > lo)
action.accept(array[lo]);
tryComplete();
}
}
new Task(null, 0, array.length).invoke();
}}
這個設計可以藉由指出,在遞歸案例中,工作在分叉其右工作之後沒有任何作用,因此可以在傳回之前直接叫用其左工作。 (這是尾遞迴移除的類比。此外,當工作的最後一個動作是分叉或叫用子工作(「尾端呼叫」時,可以優化對 tryComplete()
的呼叫,代價是讓擱置計數看起來「關閉一個」。
{@code
public void compute() {
if (hi - lo >= 2) {
int mid = (lo + hi) >>> 1;
setPendingCount(1); // looks off by one, but correct!
new Task(this, mid, hi).fork(); // right child
new Task(this, lo, mid).compute(); // direct invoke
} else {
if (hi > lo)
action.accept(array[lo]);
tryComplete();
}
}}
若要進一步優化,請注意,左工作甚至不需要存在。 我們可以繼續使用原始工作,併為每個分叉新增擱置計數,而不是建立新的工作。 此外,由於此樹狀結構中沒有任何工作 #onCompletion(CountedCompleter)
實作 方法, tryComplete
因此可以取代為 #propagateCompletion
。
{@code
public void compute() {
int n = hi - lo;
for (; n >= 2; n /= 2) {
addToPendingCount(1);
new Task(this, lo + n/2, lo + n).fork();
}
if (n > 0)
action.accept(array[lo]);
propagateCompletion();
}}
當可以預先計算暫止計數時,可以在建構函式中建立這些計數:
{@code
public static <E> void forEach(E[] array, Consumer<E> action) {
class Task extends CountedCompleter<Void> {
final int lo, hi;
Task(Task parent, int lo, int hi) {
super(parent, 31 - Integer.numberOfLeadingZeros(hi - lo));
this.lo = lo; this.hi = hi;
}
public void compute() {
for (int n = hi - lo; n >= 2; n /= 2)
new Task(this, lo + n/2, lo + n).fork();
action.accept(array[lo]);
propagateCompletion();
}
}
if (array.length > 0)
new Task(null, 0, array.length).invoke();
}}
這類類別的其他優化可能需要針對分葉步驟進行特製化類別,例如,四個,而不是每個反覆專案兩個,並使用調適性臨界值,而不是一律細分為單一元素。
<b>搜尋。</b> CountedCompleters 的樹狀結構可以在數據結構的不同部分搜尋值或屬性,並在找到結果時立即報告結果 java.util.concurrent.atomic.AtomicReference AtomicReference
。 其他人可以輪詢結果,以避免不必要的工作。 (您也可以另外 #cancel 取消其他工作,但通常更簡單且更有效率,只要讓他們注意到結果已設定,如果如此,請略過進一步的處理。使用完整分割來再次說明陣列(實際上,分葉工作幾乎一律會處理多個元素):
{@code
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();
),因為根工作完成之後不需要進一步的記賬來管理完成。
<b>錄製子工作。</b> CountedCompleter 工作,結合多個子工作的結果通常需要在 方法 #onCompletion(CountedCompleter)
中存取這些結果。 如下列類別所示(執行簡化形式的 map-reduce,其中對應和縮減都是類型 E
),在分割和征服設計中執行此動作的其中一種方法是讓每個子工作記錄其同層級,以便以 方法 onCompletion
存取它。 這項技術適用於減少合併左右結果的順序並不重要:已排序的縮減需要明確的左右指定。 上述範例中所見之其他簡化的變體也可能適用。
{@code
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
採用許多結合結果的完成設計通用的形式。 這個回呼樣式方法會在每個工作觸發一次,在擱置計數為或變成零的兩個不同內容中,如果工作本身的暫止計數為零 tryComplete
,則當其任何子工作完成並將暫止計數遞減為零時,就會觸發此回呼樣式方法。 自 caller
變數會區分大小寫。 通常,當呼叫端為 this
時,不需要採取任何動作。 否則,呼叫端自變數可以使用(通常是透過轉換)來提供要結合的值(以及/或其他值的連結)。 假設適當地使用擱置計數,內部的動作 onCompletion
會在工作及其子工作完成時發生(一次)。 此方法內不需要其他同步處理,以確保存取此工作字段或其他已完成工作的線程安全性。
<b>完成周遊。</b> 如果使用 onCompletion
來處理完成是不可套用或不方便的,您可以使用 方法和#firstComplete
#nextComplete
建立自定義周遊。 例如,若要定義 MapReducer,該 MapReducer 只會以第三個 ForEach 範例的形式分割出右手工作,完成必須共同減少未用盡的子工作連結,如下所示:
{@code
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();
}
}}
<b>觸發程式。</b> 有些 CountedCompleter 本身從未分叉,而是在其他設計中做為管道的位;包括完成一或多個異步工作會觸發另一個異步工作的人。 例如:
{@code
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();}
已在1.8中新增。
的 java.util.concurrent.CountedCompleter
Java 檔。
此頁面的部分是根據 Android 開放原始碼專案所建立和共用的工作進行修改,並根據 Creative Commons 2.5 屬性授權中所述的詞彙使用。
建構函式
CountedCompleter() |
建立沒有完成項的新 CountedCompleter 和初始暫止計數為零。 |
CountedCompleter(CountedCompleter) |
使用指定的完成項和初始暫止計數為零,建立新的 CountedCompleter。 |
CountedCompleter(CountedCompleter, Int32) |
使用指定的完成項和初始暫止計數,建立新的 CountedCompleter。 |
CountedCompleter(IntPtr, JniHandleOwnership) |
, |
屬性
Class |
傳回這個 |
Completer |
傳回在這項工作建構函式中建立的完整程式,如果沒有 |
Exception |
傳回基底計算所擲回的例外狀況,如果 |
ForkJoinTaskTag |
傳回此工作的標記。 (繼承來源 ForkJoinTask) |
Handle |
基礎Android實例的句柄。 (繼承來源 Object) |
IsCancelled |
如果此工作在正常完成之前取消,則傳 |
IsCompletedAbnormally |
|
IsCompletedNormally |
|
IsDone |
如果這項工作已完成,則傳 |
JniIdentityHashCode |
, |
JniPeerMembers |
, |
PeerReference |
, |
PendingCount |
傳回目前的暫止計數。 -或- 將暫止計數設定為指定的值。 |
RawRawResult |
傳回 由 傳回 Join()的結果,即使此工作異常完成,或 |
RawResult |
傳回計算的結果。 |
Root |
傳回目前計算的根目錄;我。 |
ThresholdClass |
, |
ThresholdType |
, |
方法
AddToPendingCount(Int32) |
將指定的值以不可部分完成的方式加入暫止計數。 |
Cancel(Boolean) |
嘗試取消此工作的執行。 (繼承來源 ForkJoinTask) |
Clone() |
建立並傳回這個 對象的複本。 (繼承來源 Object) |
CompareAndSetForkJoinTaskTag(Int16, Int16) |
以不可部分完成的方式設定此工作的標籤。 (繼承來源 ForkJoinTask) |
CompareAndSetPendingCount(Int32, Int32) |
只有在目前保留指定的預期值時,才會將暫止計數設定為指定的計數。 |
Complete(Object) |
不論擱置計數為何, |
CompleteExceptionally(Throwable) |
異常地完成此工作,如果尚未中止或取消,會導致它擲回指定的例外狀況 |
Compute() |
此工作所執行的主要計算。 |
DecrementPendingCountUnlessZero() |
如果擱置的計數為非零,則 (不可部分完成的) 會遞減它。 |
Dispose() |
, |
Dispose(Boolean) |
, |
Equals(Object) |
指出其他物件是否「等於」這個物件。 (繼承來源 Object) |
Exec() |
實作 CountedCompleters 的執行慣例。 |
FirstComplete() |
如果此工作的暫止計數為零,則傳回此工作;否則會遞減其暫止計數並傳 |
Fork() |
會安排在集區中以異步方式執行此工作,如果適用,則執行目前工作;如果不適用 |
Get() |
視需要等候計算完成,然後擷取其結果。 (繼承來源 ForkJoinTask) |
Get(Int64, TimeUnit) |
視需要等候最多指定的時間讓計算完成,然後在可用時擷取其結果。 (繼承來源 ForkJoinTask) |
GetHashCode() |
傳回此物件的雜湊碼值。 (繼承來源 Object) |
HelpComplete(Int32) |
如果此工作尚未完成,如果已知存在,則嘗試處理此工作在完成路徑上的其他未處理工作數目。 |
Invoke() |
開始執行此工作、視需要等候完成,並傳回其結果,或擲回 (unchecked) |
JavaFinalize() |
當垃圾收集決定不再參考物件時,垃圾收集行程在 物件上呼叫。 (繼承來源 Object) |
Join() |
傳回計算 #isDone 完成時的結果。 (繼承來源 ForkJoinTask) |
NextComplete() |
如果此工作沒有完成項目,請叫用 |
Notify() |
喚醒正在等候此物件監視器的單一線程。 (繼承來源 Object) |
NotifyAll() |
喚醒正在等候此物件監視器的所有線程。 (繼承來源 Object) |
OnCompletion(CountedCompleter) |
當叫用 方法 |
OnExceptionalCompletion(Throwable, CountedCompleter) |
叫用 方法或方法 |
PropagateCompletion() |
|
QuietlyComplete() |
一般不設定值即可完成這項工作。 (繼承來源 ForkJoinTask) |
QuietlyCompleteRoot() |
相當於 |
QuietlyInvoke() |
開始執行此工作,並視需要等候完成,而不會傳回其結果或擲回例外狀況。 (繼承來源 ForkJoinTask) |
QuietlyJoin() |
聯結此工作,而不傳回其結果或擲回其例外狀況。 (繼承來源 ForkJoinTask) |
Reinitialize() |
重設此工作的內部記帳狀態,允許後續 |
SetForkJoinTaskTag(Int16) |
以不可部分完成的方式設定此工作的標記值,並傳回舊的值。 (繼承來源 ForkJoinTask) |
SetHandle(IntPtr, JniHandleOwnership) |
設定 Handle 屬性。 (繼承來源 Object) |
SetRawResult(Object) |
結果承載 CountedCompleters 的方法可以選擇性地用來協助維護結果數據。 |
ToArray<T>() |
, |
ToString() |
傳回物件的字串表示。 (繼承來源 Object) |
TryComplete() |
如果暫止計數為非零,則會遞減計數;否則會 |
TryUnfork() |
嘗試取消排程此工作以執行。 (繼承來源 ForkJoinTask) |
UnregisterFromRuntime() |
, |
Wait() |
讓目前線程等候直到喚醒為止,通常是藉由em <notified/em>或<em>interrupted</em> 來喚醒它。<> (繼承來源 Object) |
Wait(Int64) |
讓目前的線程等到喚醒為止,通常是因為 <em>notified</em> 或 <em>interrupted</em>,或直到經過一定數量的實時為止。 (繼承來源 Object) |
Wait(Int64, Int32) |
讓目前的線程等到喚醒為止,通常是因為 <em>notified</em> 或 <em>interrupted</em>,或直到經過一定數量的實時為止。 (繼承來源 Object) |
明確介面實作
IJavaPeerable.Disposed() |
, |
IJavaPeerable.DisposeUnlessReferenced() |
, |
IJavaPeerable.Finalized() |
, |
IJavaPeerable.JniManagedPeerState |
, |
IJavaPeerable.SetJniIdentityHashCode(Int32) |
, |
IJavaPeerable.SetJniManagedPeerState(JniManagedPeerStates) |
, |
IJavaPeerable.SetPeerReference(JniObjectReference) |
, |
擴充方法
JavaCast<TResult>(IJavaObject) |
執行 Android 執行時間檢查的類型轉換。 |
JavaCast<TResult>(IJavaObject) |
, |
GetJniTypeName(IJavaPeerable) |
, |
GetAsync(IFuture) |
, |
GetAsync(IFuture, Int64, TimeUnit) |
, |