public abstract class CountedCompleter<T> extends ForkJoinTask<T>
ForkJoinTask
です。CountedCompleterは、一般にサブタスクの停止やブロックが発生した場合は他の形式のForkJoinTaskより堅牢ですが、直感的にプログラミングしにくくなります。CountedCompleterの使用方法は他の完了ベースのコンポーネント(CompletionHandler
など)と同様ですが、完了アクションonCompletion(CountedCompleter)
をトリガーするためには、1つではなく複数の保留完了が必要になることがあります。別の方法で初期化された場合を除き、保留カウントはゼロから始まりますが、setPendingCount(int)
、addToPendingCount(int)
およびcompareAndSetPendingCount(int, int)
メソッドを使用して(原子的に)変更できます。tryComplete()
を呼び出したときに、保留アクションのカウントがゼロでない場合は、値が減らされます。それ以外の場合は、完了アクションが実行され、このコンプリータ自体がコンプリータを持っている場合はそのコンプリータで処理が続行されます。Phaser
やSemaphore
などの関連する同期化コンポーネントと同様に、これらのメソッドは内部のカウントにしか影響を与えず、それ以上の内部登録を確立しません。特に、保留タスクの識別情報は保持されません。次に示すように、必要に応じて保留タスクまたはそれらの結果の一部または全部を記録するサブクラスを作成できます。次に示すように、完了のトラバースのカスタマイズをサポートするユーティリティ・メソッドも提供されます。ただし、CountedCompleterは基本的な同期化メカニズムのみを提供するため、一連の関連する用途に適したリンク、フィールドおよび追加のサポート・メソッドを保持するその他の抽象サブクラスを作成するときに便利な場合があります。
具象CountedCompleterクラスは、ほとんどのケースで(次に示すように)復帰する前にtryComplete()
を1回呼び出すcompute()
メソッドを定義する必要があります。このクラスでは、オプションで、正常な完了時にアクションを実行するonCompletion(CountedCompleter)
メソッドと、例外の発生時にアクションを実行するonExceptionalCompletion(Throwable, CountedCompleter)
メソッドをオーバーライドすることもできます。
ほとんどの場合、CountedCompleterは結果を生成しません。通常はCountedCompleter<Void>
として宣言され、結果値として常にnull
を返します。それ以外の場合は、getRawResult()
メソッドをオーバーライドして、join()、invoke()
および関連メソッドから結果を提供するようにしてください。一般に、このメソッドは完了時の結果を保持するCountedCompleterオブジェクトのフィールド(または1つ以上のフィールドの関数)の値を返す必要があります。setRawResult(T)
メソッドは、デフォルトではCountedCompleterに何の影響も与えません。適用可能なケースはほとんどありませんが、このメソッドをオーバーライドして、結果データを持つ他のオブジェクトやフィールドを保持することも可能です。
それ自体ではコンプリータを持たない(つまり、getCompleter()
がnull
を返す)CountedCompleterは、この追加機能を含む通常のForkJoinTaskとして使用できます。ただし、別のコンプリータを持つコンプリータは、他の計算の内部ヘルパーとしてのみ機能するため、(ForkJoinTask.isDone()
などのメソッドで報告される)それ自体のタスク・ステータスは不定です。このステータスは、complete(T)
、ForkJoinTask.cancel(boolean)
、ForkJoinTask.completeExceptionally(Throwable)
の明示的な呼出し時、またはcompute
メソッドの例外完了時にのみ変更されます。例外完了時に、タスクのコンプリータ(およびそのコンプリータ、以下同様)が存在し、まだ完了していない場合は、それらに例外が中継されます。同様に、内部のCountedCompleterを取り消しても、そのコンプリータに対するローカルの効果しかないため、多くの場合有効ではありません。
使用例。
並列の再帰的分解。CountedCompleterは、RecursiveAction
で使用されるものと同様のツリーに配置できます。ただし、それらの設定では通常、異なる方法で構築が行われます。この場合、各タスクのコンプリータは、計算ツリーではタスクの親になります。必要な登録作業がやや多くなりますが、配列またはコレクションの各要素に時間のかかる(それ以上分割できない)オペレーションを適用する場合(特に、入出力などの固有の差違またはガベージ・コレクションなどの補助効果のいずれかが原因で、そのオペレーションの完了にかかる時間が要素によって大幅に異なる場合)、CountedCompleterはより適切な方法である可能性があります。CountedCompleterは独自の継続を提供するため、他のスレッドはCountedCompleterの実行の待機をブロックする必要はありません。
たとえば、2分割の再帰的分解を使用して作業を単体(リーフ・タスク)に分割するクラスの初期バージョンを次に示します。作業が個別の呼出しに分割されている場合でも、通常はリーフ・タスクを直接フォークするより、スレッド間通信が減少し、負荷分散が向上するツリーベースの手法をお薦めします。再帰的なケースでは、完了するサブタスクの各ペアの2番目がその親の完了をトリガーします(結果の結合が行われないため、onCompletion
メソッドのデフォルトの無操作実装はオーバーライドされません)。staticユーティリティ・メソッドがベース・タスクを設定し、それを呼び出します(ここでは、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
の呼出しにフォール・スルーせずに)その左側のタスクの実行時に復帰するため、保留カウントは1に設定されます。
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();
}
このようなクラスをさらに改良するには、保留カウントをコンストラクタで設定できるように事前計算する、クラスをリーフ・ステップ用に特化する、反復ごとに2個ではなくたとえば4個に分割する、常に単一の要素に分割するかわりに適応的なしきい値を使用する、などの必要があります。
検索。CountedCompleterのツリーでは、データ構造の様々な部分に含まれる値またはプロパティを検索し、結果が見つかった場合はただちにAtomicReference
に結果を報告できます。他のタスクはその結果をポーリングして、不要な作業を回避できます。(さらに、他のタスクを取り消すこともできますが、通常は結果が設定されたことをそれらに通知し、その場合は後続の処理を省略させるのがより簡単で効率的です。)完全なパーティション化を使用する配列を使って再度説明します(この場合も、実際には、リーフ・タスクはほとんど常に複数の要素を処理します)。
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)
メソッドでこれらの結果にアクセスする必要があります。次の(マッピングとリダクションの型がすべてE
である簡易形式のマップ・リデュースを実行する)クラスに示すように、分割統治型の設計でこれを行う方法の1つは、各サブタスクにその兄弟を記録させ、onCompletion
メソッドでそれにアクセスできるようにすることです。この手法は、左と右の結果を結合する順序が問題にならないようなリダクションに適用されます。順序付けされたリダクションでは、左と右を明示的に指定する必要があります。前の例に示した他の合理化方法のバリアントを適用することもできます。
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
メソッドは結果を結合する多くの完了設計に共通する形式を取っています。このコールバック形式のメソッドは、保留カウントがゼロである(またはゼロになる)2つの異なるコンテキストのいずれかで、タスクごとに1回トリガーされます。つまり、(1)tryComplete
の呼出し時にその保留カウントがゼロである場合は、そのタスク自体によってトリガーされ、(2)そのサブタスクのいずれかが完了し、保留カウントをゼロに減らしたときは、そのサブタスクによってトリガーされます。caller
引数はケースを区別します。ほとんどの場合、呼出し側がthis
であれば、アクションは不要です。それ以外の場合、caller引数は結合される値(または他の値へのリンク、あるいはその両方)を提供するために(通常はキャストを介して)使用されます。保留カウントが適切に使用されていれば、onCompletion
内のアクションはタスクおよびそのサブタスクの完了時に(1回)発生します。このタスクまたは他の完了したタスクのフィールドへのアクセスのスレッド安全性を確保するために、このメソッド内に同期化を追加する必要はありません。
完了のトラバース。onCompletion
を使用して完了を処理することが不適当または不都合である場合は、firstComplete()
およびnextComplete()
メソッドを使用してカスタム・トラバースを作成できます。たとえば、3番目のForEachの例の形式で右側のタスクを分割するのみの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();
}
}
トリガー。CountedCompleterの中には、それ自体はフォークされないが、かわりに他の設計の構成要素の一部として機能するものがあります。これには、1つ以上の非同期タスクの完了が別の非同期タスクをトリガーするCountedCompleterが含まれます。たとえば、
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();
修飾子 | コンストラクタと説明 |
---|---|
protected |
CountedCompleter()
コンプリータを持たず、初期の保留カウントがゼロである新しいCountedCompleterを作成します。
|
protected |
CountedCompleter(CountedCompleter<?> completer)
指定されたコンプリータと、保留カウントの初期値ゼロを使用して、新しいCountedCompleterを作成します。
|
protected |
CountedCompleter(CountedCompleter<?> completer, int initialPendingCount)
指定されたコンプリータと初期保留カウントを使用して、新しいCountedCompleterを作成します。
|
修飾子と型 | メソッドと説明 |
---|---|
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()
CountedCompleterの実行規則を実装します。
|
CountedCompleter<?> |
firstComplete()
このタスクの保留カウントがゼロの場合は、このタスクを返します。それ以外の場合は、その保留カウントを減分し、
null を返します。 |
CountedCompleter<?> |
getCompleter()
このタスクのコンストラクタで確立されたコンプリータがある場合はそれを返し、ない場合は
null を返します。 |
int |
getPendingCount()
現在の保留カウントを返します。
|
T |
getRawResult()
計算の結果を返します。
|
CountedCompleter<?> |
getRoot()
現在の計算のルートを返します。つまり、このタスクにコンプリータがない場合はこのタスクを返し、それ以外の場合はそのコンプリータのルートを返します。
|
void |
helpComplete(int maxTasks)
このタスクが完了していない場合に、このタスクがその完了パスに含まれる他の未処理タスクの処理を、指定された数を限度に試行します(そのようなタスクが存在することがわかっている場合)。
|
CountedCompleter<?> |
nextComplete()
このタスクにコンプリータがない場合は、
ForkJoinTask.quietlyComplete() を呼び出し、null を返します。 |
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)
結果を生成するCountedCompleterが結果データを保持するためにオプションで使用するメソッドです。
|
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()
ForkJoinTask.quietlyComplete()
を呼び出し、null
を返します。または、コンプリータの保留カウントがゼロ以外の場合は、その保留カウントを減分し、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
- 値 バグまたは機能を送信
詳細なAPIリファレンスおよび開発者ドキュメントについては、Java SEのドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright© 1993, 2014, Oracle and/or its affiliates. All rights reserved.