public abstract class ClassValue<T> extends Object
ClassValue
を使ってキャッシュ内に格納できます。修飾子 | コンストラクタと説明 |
---|---|
protected |
ClassValue()
唯一のコンストラクタです。
|
protected abstract T computeValue(Class<?> type)
ClassValue
について、指定されたクラスの派生値を計算します。
このメソッドは、get
メソッドで最初に値にアクセスしたスレッド内で呼び出されます。
通常、このメソッドが呼び出されるのはクラスごとに最大 1 回ですが、remove
が呼び出された場合には再度呼び出される可能性もあります。
このメソッドから例外がスローされた場合、対応する get
呼び出しはその例外で異常終了し、クラス値は記録されません。
type
- クラス値を計算する必要のある型ClassValue
に関連付けられた新しい計算値get(java.lang.Class<?>)
, remove(java.lang.Class<?>)
public T get(Class<?> type)
computeValue
メソッドを呼び出して値が取得されます。
クラスへの値の実際のインストールは、原子的に実行されます。その時点で、いくつかの競合スレッドに計算値が含まれていた場合、その 1 つが選択され、それがすべての競合スレッドに返されます。
type
パラメータは通常クラスになりますが、インタフェース、プリミティブ型 (int.class
など)、void.class
といった任意の型にすることもできます。
remove
呼び出しが存在しない場合、クラス値の状態図は単純になります。初期化解除済みと初期化済みです。remove
呼び出しを行う場合の値監視の規則は、より複雑なものとなります。詳細については、remove
のドキュメントを参照してください。
type
- クラス値を計算または取得する必要のある型ClassValue
に関連付けられた現在値NullPointerException
- 引数が null の場合remove(java.lang.Class<?>)
, computeValue(java.lang.Class<?>)
public void remove(Class<?> type)
computeValue
メソッドの呼び出しによって値がふたたび初期化されます。このため、指定されたクラスに対して computeValue
メソッドの追加呼び出しが発生する可能性があります。
get
呼び出しと remove
呼び出しの相互作用を説明するためには、初期化解除済み状態と初期化済み状態との間の相互遷移を考慮してクラス値の状態遷移をモデル化する必要があります。それには、これらの状態にゼロから順に番号を付けますが、その際、初期化解除済み (または削除済み) 状態の番号は偶数、初期化済み (または再初期化済み) 状態の番号は奇数になるようにします。
スレッド T
が状態 2N
のクラス値を削除する場合、そのクラス値はすでに初期化解除されているので、何も起こりません。それ以外の場合、状態は原子的に 2N+1
に進められます。
スレッド T
が状態 2N
のクラス値を照会する場合、スレッドはまず、クラス値を状態 2N+1
に初期化するために、computeValue
を呼び出してその結果の値をインストールします。
T
が新しく計算された値のインストールを試みる際に、状態がまだ 2N
であれば、その計算値でクラス値が初期化され、状態が 2N+1
に進められます。
それ以外の場合は、新しい状態が偶数、奇数のいずれであっても、T
は新しく計算された値を破棄し、get
操作を再試行します。
破棄と再試行は重要な条件です。そうしなかった場合、T
は大きな損害をもたらす古い値をインストールしてしまう可能性があるからです。例を示します。
T
が CV.get(C)
を呼び出し、状態 2N
を確認する
T
が時間に依存する値 V0
をすばやく計算し、そのインストール準備を整える
T
が運悪くページングイベントまたはスケジューリングイベントに遭遇し、長期間のスリープ状態に入る
T2
も CV.get(C)
を呼び出し、状態 2N
を確認する
T2
が同じような時間に依存する値 V1
をすばやく計算し、それを CV.get(C)
にインストールする
T2
(または 3 つ目のスレッド) が CV.remove(C)
を呼び出し、T2
の作業を元に戻す
T2
の以上のアクションが何度か繰り返される
V1
, V2
, ...
T
が復帰して、V0
のインストールを試みる。これは失敗することになる
CV.computeValue
は V1
などの計算中に、ロックを使って時間に依存する状態を適切に監視できるものと仮定できます。それでも古い値の危険は消えません。なぜなら、T
内で computeValue
が返されるのと新しい値のインストールとの間には、時間のズレがあるからです。この期間中のユーザー同期は不可能です。type
- クラス値を削除する必要のある型NullPointerException
- 引数が null の場合 バグまたは機能を送信
詳細な API リファレンスおよび開発者ドキュメントについては、Java SE のドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright © 1993, 2013, Oracle and/or its affiliates. All rights reserved.