Module  java.base
软件包  java.lang.invoke

Class SwitchPoint



  • public class SwitchPoint
    extends Object

    A SwitchPoint是可以将状态转换发布到其他线程的对象。 切换点最初处于有效状态,但可随时更改为无效状态。 无效无法撤销。 切换点可以将守卫的一对方法句柄组合成守卫的委托者 守卫的委托者是一个方法句柄,它将一个旧的方法句柄委托。 切换点的状态确定两者中的哪一个获得授权。

    单个切换点可用于控制任意数量的方法句柄。 (间接地,它可以控制任何数量的呼叫站点)。这是通过使用单个切换点作为工厂来完成的,将任意数量的守卫方法句柄对组合成守卫的委托者。

    当一个守卫的委托者是从一个守卫的对创建的时候,该对被包裹在一个新的方法句柄M ,它与创建它的切换点永久关联。 每一对由目标T和后退F 当切换点有效时,调用M被委派给T 无效后,调用将被委派给F

    无效是全局和立即的,就像在每次调用M时,切换点包含一个易失性布尔变量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, hasBeenInvalidated会一直这样做。 另一方面,由于另一个线程的请求,其他线程可见的有效切换点可能在任何时候无效。

        由于无效是一个全局和立即的操作,所以在有效的切换点上执行此查询必须与可能导致无效的任何其他线程进行内部排序。 因此,该查询可能是昂贵的。 建立一个查询交换点s的无效状态的布尔值方法句柄的建议方法是调用s.guardWithTestconstant真假方法句柄。

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

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

        这个操作可能是昂贵的,应该谨慎使用。 如果可能,应对缓冲器进行缓冲,以便对交换点集合进行批处理。

        如果switchPoints包含一个空元素,则会产生一个NullPointerException 在这种情况下,方法返回异常之前,可能会处理数组中的一些非空元素。 哪些元素(如果有的话)是依赖于实现的。

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

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

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