public class MutableCallSite extends CallSite
MutableCallSite
は、ターゲット変数の動作が通常のフィールドと同じであるようなCallSite
です。MutableCallSite
にリンクされたinvokedynamic
命令は、すべての呼出しをそのサイトの現在のターゲットに委譲します。可変コール・サイトの動的インボーカも、各呼出しをそのサイトの現在のターゲットに委譲します。
メソッド・ハンドル・チェーンに状態変数を導入する可変コール・サイトの例を、次に示します。
MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class)); MethodHandle MH_name = name.dynamicInvoker(); MethodType MT_str1 = MethodType.methodType(String.class); MethodHandle MH_upcase = MethodHandles.lookup() .findVirtual(String.class, "toUpperCase", MT_str1); MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase); name.setTarget(MethodHandles.constant(String.class, "Rocky")); assertEquals("ROCKY", (String) worker1.invokeExact()); name.setTarget(MethodHandles.constant(String.class, "Fred")); assertEquals("FRED", (String) worker1.invokeExact()); // (mutation can be continued indefinitely)
同じコール・サイトをいくつかの場所で一度に使用できます。
MethodType MT_str2 = MethodType.methodType(String.class, String.class); MethodHandle MH_cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?"); MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear); assertEquals("Fred, dear?", (String) worker2.invokeExact()); name.setTarget(MethodHandles.constant(String.class, "Wilma")); assertEquals("WILMA", (String) worker1.invokeExact()); assertEquals("Wilma, dear?", (String) worker2.invokeExact());
ターゲット値の非同期: 可変コール・サイトのターゲットに書き込んでも、ほかのスレッドがその更新された値を認識するようにはなりません。更新されたコール・サイトに関する適切な同期アクションを実行しないスレッドは、古いターゲット値をキャッシュに入れ、新しいターゲット値の使用を無期限に遅らせる可能性があります。(これは、オブジェクト・フィールドに適用されるJavaメモリー・モデルの通常の結果です。)
syncAll
操作は、ほかの同期が存在していなくてもスレッドが新しいターゲット値を受け入れるように強制するための手段を提供します。
更新頻度の高いターゲット値では、代わりに揮発性コール・サイトの使用を検討してください。
コンストラクタと説明 |
---|
MutableCallSite(MethodHandle target)
初期ターゲット・メソッド・ハンドルを持つコール・サイト・オブジェクトを作成します。
|
MutableCallSite(MethodType type)
指定されたメソッド型を持つ空のコール・サイト・オブジェクトを作成します。
|
修飾子と型 | メソッドと説明 |
---|---|
MethodHandle |
dynamicInvoker()
このコール・サイトにリンクされているinvokedynamic命令と同等のメソッド・ハンドルを生成します。
|
MethodHandle |
getTarget()
コール・サイトのターゲット・メソッドを返しますが、これは、
MutableCallSite の通常のフィールドのように振る舞います。 |
void |
setTarget(MethodHandle newTarget)
このコール・サイトのターゲット・メソッドを通常の変数として更新します。
|
static void |
syncAll(MutableCallSite[] sites)
指定された配列内のコール・サイトごとに同期処理を実行しますが、その際、いずれかのコール・サイトのターゲットから以前にロードされたキャッシュ値をすべて破棄することを、ほかのすべてのスレッドに対して強制します。
|
public MutableCallSite(MethodType type)
IllegalStateException
をスローするような、指定された型のメソッド・ハンドルに設定されます。
コール・サイトの型が、指定された型に永続的に設定されます。
このCallSite
オブジェクトがブートストラップ・メソッドから返されたりほかの何らかの方法で呼び出されたりする前に、通常はsetTarget
呼出し経由でより有用なターゲット・メソッドがこのオブジェクトに提供されます。
type
- このコール・サイトのメソッド型NullPointerException
- 提案された型がnullの場合public MutableCallSite(MethodHandle target)
target
- コール・サイトの初期ターゲットとなるメソッド・ハンドルNullPointerException
- 提案されたターゲットがnullの場合public final MethodHandle getTarget()
MutableCallSite
の通常のフィールドのように振る舞います。
getTarget
のメモリーとの相互作用は、通常の変数(配列の要素や非揮発性のfinalフィールドなど)から読取りを行う場合と同じです。
特に、現在のスレッドは、以前のメモリーからのターゲットの読取り結果を再利用することを選択する可能性があり、別のスレッドによるターゲットへの最新の更新を認識できない可能性があります。
getTarget
、クラス: CallSite
setTarget(java.lang.invoke.MethodHandle)
public void setTarget(MethodHandle newTarget)
メモリーとの相互作用は、通常の変数(配列の要素や非揮発性のfinalフィールドなど)への書込みを行う場合と同じです。
特に、無関係のスレッドは、メモリーからの読取りを実行するまで、更新されたターゲットを認識できない可能性があります。より確実に保証するには、与えられた任意のコール・サイトで使用されるブートストラップ・メソッドまたはターゲット・メソッドあるいはその両方に、適切な処理を組み込みます。
setTarget
、クラス: CallSite
newTarget
- 新しいターゲットNullPointerException
- 提案された新しいターゲットがnullの場合WrongMethodTypeException
- 提案された新しいターゲットのメソッド型が以前のターゲットと異なる場合getTarget()
public final MethodHandle dynamicInvoker()
このメソッドは次のコードと同等です。
MethodHandle getTarget, invoker, result; getTarget = MethodHandles.publicLookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class)); invoker = MethodHandles.exactInvoker(this.type()); result = MethodHandles.foldArguments(invoker, getTarget)
dynamicInvoker
、クラス: CallSite
public static void syncAll(MutableCallSite[] sites)
この処理では、すでに古いターゲット値に対して開始された呼出しが取り消されることは一切ありません。(Javaでは未来へのタイム・トラベルのみがサポートされます。)
全体の効果としては、各コール・サイトのターゲットの将来のすべての読取り元に、直近で格納された値の受け入れを強制することです。(「直近」は、syncAll
自身を基準にしたものと見なされます。)逆に言えば、すべての読取り元が(何らかの方法で)各コール・サイトのターゲットの以前のバージョンをすべてキャッシュから削除するまで、syncAll
の呼出しがブロックする可能性があります。
setTarget
とsyncAll
の呼出しは一般に、競合状態を回避できるように、何らかの種類の相互排他の下で実行すべきです。読取り元スレッドは、値をインストールするsetTarget
呼び出しと同じくらい早い時期に(値を確認するsyncAll
に先だって)ターゲットの更新を認識する可能性があります。一方、読取り元スレッドが、(更新版を伝えようとするsetTarget
のあと) syncAll
呼出しが返るまで、以前のバージョンのターゲットを認識する可能性もあります。
この処理は、コストが高くなる可能性が高いため、できるかぎり使用しないようにしてください。可能であればそれをバッファし、一連のコール・サイトのバッチ処理を行えるようにしてください。
sites
にnull要素が含まれていると、NullPointerException
が発行されます。この場合、メソッドが異常終了で返る前に、配列内のnullでない要素がいくつか処理される可能性があります。それらがどの要素であるか(存在する場合)は、実装に依存します。
個々のコール・サイトS
について、明らかな影響を次に示します。
V
の作成と書込みが行われます。JMMでの定義に従い、この書込みはグローバル同期イベントになります。
V
への揮発性書込みの前に起こったものとされます。(これは一部の実装では、現在のスレッドがグローバル解放処理を実行することを意味します。)
S
の現在のターゲットへの書込みは、V
への揮発性書込みの前に起こったものとされます。
V
への揮発性書込みは、グローバル同期順序で(実装固有の方法で)配置されます。
T
(現在のスレッド以外)を考えます。T
は、(グローバル同期順序で) V
への揮発性書込みのあとで同期アクションA
を実行した場合、その結果、S
の現在のターゲット、またはS
のターゲットに対する読取りを実行した場合はそのターゲットへの後続の書き込み、のどちらかを認識する必要があります。(この制約は「同期順序の一貫性」と呼ばれます。)
V
は除去されません(書き込まれた値が不確定で読み取られた値が使用されない場合でも)。
T
がアクションA
の直後にV
の揮発性読取りを実行したかのようになります。この読取りは、T
のローカル・アクション順序で、S
のターゲットの将来のあらゆる読取りの前に起こります。それはまるで、実装が、T
によるS
のターゲットの読取りを任意に選択し、それに先だってV
の読取りを強制することで、新しいターゲット値の伝達を保証したかのようになります。
実装はJavaメモリー・モデルの制約に従うかぎり、ほかのスレッド(上ではT
)がS
のターゲットの以前の値を使用し続けている間、syncAll
の処理の完了を遅らせてもかまいません。ただし、実装では(いつものように)、ライブロックを避け、更新されたターゲットを考慮することを最終的にはすべてのスレッドに要求することをお薦めします。
解説: syncAll
はパフォーマンス上の理由により、単一のコール・サイト上の仮想メソッドではなく、一連のコール・サイトに適用されます。一部の実装では、1つ以上の同期処理のために固定の大きなオーバーヘッド・コストが発生する一方で、コール・サイトを1つ追加するごとに増えるコストが小さい可能性があります。いずれにせよ、ほかのスレッドに何らかの方法で割込みを行って更新されたターゲット値を知らせなければいけない可能性があるため、この処理はおそらく高コストになります。ただし、いくつかのコール・サイトを同期させる単一の呼出しは、いずれかのサイトだけに対する呼出しを複数回行うのと形式上は同じ効果がある、ということは言えます。
実装上の注意: MutableCallSite
の単純な実装では、可変コール・サイトのターゲットとして揮発性変数が使用される可能性があります。そのような実装ではsyncAll
メソッドが無操作になる可能性がありますが、それは、前述のJMM動作に準拠しています。
sites
- 同期するコール・サイトの配列NullPointerException
- sites
配列参照がnullであるか、配列内にnullが含まれている場合 バグまたは機能を送信
詳細なAPIリファレンスおよび開発者ドキュメントについては、Java SEのドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright© 1993, 2014, Oracle and/or its affiliates. All rights reserved.