- java.lang.Object
-
- java.lang.ClassValue<T>
-
public abstract class ClassValue<T> extends Object
計算値を(潜在的に)すべての型に遅延して関連付けます。 たとえば動的言語は、メッセージ送信コール・サイトで検出されたクラスごとにメッセージ・ディスパッチ表を構築する必要がある場合に、メッセージ送信をすばやく実行するために必要な情報を、検出されたクラスごとにClassValue
を使ってキャッシュ内に格納できます。- 導入されたバージョン:
- 1.7
-
-
コンストラクタのサマリー
コンストラクタ 修飾子 コンストラクタ 説明 protected
ClassValue()
唯一のコンストラクタです。
-
-
-
メソッドの詳細
-
computeValue
protected abstract T computeValue(Class<?> type)
このClassValue
について、指定されたクラスの派生値を計算します。このメソッドは、
get
メソッドで最初に値にアクセスしたスレッド内で呼び出されます。通常、このメソッドが呼び出されるのはクラスごとに最大1回ですが、
remove
が呼び出された場合には再度呼び出される可能性もあります。このメソッドから例外がスローされた場合、対応する
get
呼出しはその例外で異常終了し、クラス値は記録されません。- パラメータ:
type
- クラス値を計算する必要のある型- 戻り値:
- 指定されたクラスまたはインタフェースについて、この
ClassValue
に関連付けられた新しい計算値 - 関連項目:
get(java.lang.Class<?>)
,remove(java.lang.Class<?>)
-
get
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<?>)
-
remove
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
などを計算する際に、時間依存状態を正しく観察することができます。これは、computeValue
の戻りとT
と新しい値のインストール。 この期間中のユーザー同期は不可能です。- パラメータ:
type
- クラス値を削除する必要のある型- 例外:
NullPointerException
- 引数がnullの場合
-
-