モジュール java.base
パッケージ java.lang

クラスClassValue<T>


  • public abstract class ClassValue<T>
    extends Object
    計算値を(潜在的に)すべての型に遅延して関連付けます。 たとえば動的言語は、メッセージ送信コール・サイトで検出されたクラスごとにメッセージ・ディスパッチ表を構築する必要がある場合に、メッセージ送信をすばやく実行するために必要な情報を、検出されたクラスごとにClassValueを使ってキャッシュ内に格納できます。
    導入されたバージョン:
    1.7
    • コンストラクタのサマリー

      コンストラクタ 
      修飾子 コンストラクタ 説明
      protected ClassValue()
      唯一のコンストラクタです。
    • メソッドのサマリー

      修飾子と型 メソッド 説明
      protected abstract T computeValue​(クラス<?> type)
      このClassValueについて、指定されたクラスの派生値を計算します。
      T get​(クラス<?> type)
      指定されたクラスの値を返します。
      void remove​(クラス<?> type)
      指定されたクラスに関連付けられた値を削除します。
    • コンストラクタの詳細

      • ClassValue

        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は大きな損害をもたらす古い値をインストールしてしまう可能性があるからです。 次に例を示します。

        • TCV.get(C)を呼び出し、状態2Nを確認する
        • Tが時間に依存する値V0をすばやく計算し、そのインストール準備を整える
        • Tが運悪くページング・イベントまたはスケジューリング・イベントに遭遇し、長期間のスリープ状態に入る
        • 一方、T2CV.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の場合