模块  java.base
软件包  java.lang.invoke

Class SwitchPoint


  • public class SwitchPoint
    extends Object

    SwitchPoint是一个可以将状态转换发布到其他线程的对象。 切换点最初处于有效状态,但可以随时更改为无效状态。 失效无法逆转。 切换点可以将一组受保护的方法句柄组合成一个受保护的委托人 受保护的委托者是一个方法句柄,它委托给一个旧的方法句柄。 切换点的状态决定了两者中的哪一个获得了委托。

    单个切换点可用于控制任意数量的方法句柄。 (因此,间接地,它可以控制任意数量的呼叫站点。)这可以通过将单个切换点用作工厂来将任意数量的保护方法句柄对组合到受保护的委托者中来完成。

    当从受保护的对创建受保护的委托者时,该对被包裹在新方法句柄M ,该句柄永久地与创建它的切换点相关联。 每对由目标T和后备F 当切换点有效时,对M调用将委派给T 失效后,调用将委派给F

    失效是全局和立即的,就好像切换点包含每次调用M的volatile布尔变量M 失效也是永久性的,这意味着切换点只能改变状态一次。 无效后,切换点将始终委托给F 此时guardWithTest可以忽略T并返回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
    • 构造方法详细信息

      • SwitchPoint

        public SwitchPoint()
        创建一个新的切换点。
    • 方法详细信息

      • hasBeenInvalidated

        public boolean hasBeenInvalidated()
        确定此切换点是否已失效。

        讨论:由于失效的单向性,一旦切换点开始为hasBeenInvalidated返回true,它将来总会这样做。 另一方面,由于另一个线程的请求,其他线程可见的有效切换点可能随时无效。

        由于失效是一个全局和立即操作,因此在有效切换点上执行此查询必须在内部对任何其他可能导致失效的线程进行排序。 因此,该查询可能很昂贵。 构建查询切换点s的无效状态的布尔值方法句柄的推荐方法是在s.guardWithTest上调用s.guardWithTest true和false方法句柄。

        结果
        如果此切换点已失效,则为true
      • invalidateAll

        public static void invalidateAll​(SwitchPoint[] switchPoints)
        将所有给定的切换点设置为无效状态。 执行此调用后,任何线程都不会观察到任何切换点处于有效状态。

        这种操作可能很昂贵,应该谨慎使用。 如果可能,应对其进行缓冲,以便在多组切换点上进行批处理。

        如果switchPoints包含null元素,则将引发NullPointerException 在这种情况下,可以在方法异常返回之前处理数组中的一些非null元素。 这些元素(如果有的话)取决于实现。

        讨论:出于性能原因, invalidateAll不是单个切换点上的虚拟方法,而是适用于一组切换点。 一些实现可能导致用于处理一个或多个无效操作的大的固定开销成本,但是对于每个额外的无效而言会产生小的增量成本。 在任何情况下,该操作可能是昂贵的,因为可能必须以某种方式中断其他线程以使它们注意到更新的切换点状态。 然而,可以观察到,使多个切换点无效的单个调用具有与许多调用相同的正式效果,每个调用仅在一个切换点上。

        实现注意: SwitchPoint简单实现可以使用私有MutableCallSite来发布切换点的状态。 在这种实现中, invalidateAll方法可以简单地改变呼叫站点的目标,并向synchronize发出一个呼叫所有私人呼叫站点。

        参数
        switchPoints - 要同步的一组呼叫站点
        异常
        NullPointerException - if the switchPoints array reference is null or the array contains a null