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

クラスSwitchPoint

java.lang.Object
java.lang.invoke.SwitchPoint

public class SwitchPoint extends Object

SwitchPointは、状態遷移をほかのスレッドに発行できるオブジェクトです。 スイッチ・ポイントは、最初は有効状態になっていますが、いつでも無効状態に変更される可能性があります。 無効化を取り消すことはできません。 スイッチ・ポイントは、保護対象ペアのメソッド・ハンドルを組み合わせて1つの保護デリゲータを作成できます。 保護デリゲータとは、古いメソッド・ハンドルのいずれかに委譲するようなメソッド・ハンドルのことです。 スイッチ・ポイントの状態によって、2つのどちらに委譲されるかが決まります。

単一のスイッチ・ポイントを使って任意の数のメソッド・ハンドルを制御できます。 (したがって、これは間接的に任意の数のコール・サイトを制御できます。) これを行うには、任意の数の保護対象メソッド・ハンドル・ペアを組み合わせて保護デリゲータを作成するためのファクトリとして、単一のスイッチ・ポイントを使用します。

保護対象ペアから保護デリゲータが作成されるときに、それらのペアは新しいメソッド・ハンドルM内にラップされますが、新しいメソッド・ハンドルは、その作成元であるスイッチ・ポイントに永続的に関連付けられます。 各ペアはターゲットTとフォール・バックFで構成されます。 スイッチ・ポイントが有効な間は、Mの呼出しがTに委譲されます。 それが無効化されたあとは、呼出しがFに委譲されます。

Mが呼び出されるたびに参照される揮発性のboolean変数がスイッチ・ポイントに含まれているかのように、無効化はグローバルかつ即時的なものになります。 無効化は永続的でもありますが、これは、スイッチ・ポイントの状態を変更できるのは1回だけであることを意味します。 無効化されたあとのスイッチ・ポイントは、常にFに委譲します。 その時点で、guardWithTestTを無視し、Fを返す可能性があります。

実際のスイッチ・ポイントの例を、次に示します。


 MethodHandle MH_strcat = MethodHandles.lookup()
     .findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
 SwitchPoint spt = new SwitchPoint();
 assert(!spt.hasBeenInvalidated());
 // the following steps may be repeated to re-use the same switch point:
 MethodHandle worker1 = MH_strcat;
 MethodHandle worker2 = MethodHandles.permuteArguments(MH_strcat, MH_strcat.type(), 1, 0);
 MethodHandle worker = spt.guardWithTest(worker1, worker2);
 assertEquals("method", (String) worker.invokeExact("met", "hod"));
 SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
 assert(spt.hasBeenInvalidated());
 assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
 

解説: スイッチ・ポイントはサブクラス化しなくても有用です。 これらはサブクラス化することもできます。 これは、アプリケーション固有の無効化ロジックをスイッチ・ポイントに関連付ける場合に役立つ可能性があります。 スイッチ・ポイントと、それが生成および消費するメソッド・ハンドルとの間には、永続的な関係は一切存在しません。 ガベージ・コレクタは、スイッチ・ポイントによって生成または消費されたメソッド・ハンドルを、スイッチ・ポイント自体の存続期間とは無関係に収集する可能性があります。

実装上のノート: スイッチ・ポイントは、MutableCallSiteに基づいておおよそ次のように実装されているかのように動作します。


 public class SwitchPoint {
     private static final MethodHandle
         K_true  = MethodHandles.constant(boolean.class, true),
         K_false = MethodHandles.constant(boolean.class, false);
     private final MutableCallSite mcs;
     private final MethodHandle mcsInvoker;
     public SwitchPoint() {
         this.mcs = new MutableCallSite(K_true);
         this.mcsInvoker = mcs.dynamicInvoker();
     }
     public MethodHandle guardWithTest(
             MethodHandle target, MethodHandle fallback) {
         // Note:  mcsInvoker is of type ()boolean.
         // Target and fallback may take any arguments, but must have the same type.
         return MethodHandles.guardWithTest(this.mcsInvoker, target, fallback);
     }
     public static void invalidateAll(SwitchPoint[] spts) {
         List<MutableCallSite> mcss = new ArrayList<>();
         for (SwitchPoint spt : spts)  mcss.add(spt.mcs);
         for (MutableCallSite mcs : mcss)  mcs.setTarget(K_false);
         MutableCallSite.syncAll(mcss.toArray(new MutableCallSite[0]));
     }
 }
 

導入されたバージョン:
1.7