java mutable_java11教程--类MutableCallSite用法

A MutableCallSite是CallSite,其目标变量的行为类似于普通字段。

链接到MutableCallSite的invokedynamic指令委托对站点当前目标的所有调用。

可变调用站点的dynamic invoker还会将每次调用委派给站点的当前目标。

下面是一个可变调用站点的示例,它将状态变量引入方法句柄链。

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操作提供了一种强制线程接受新目标值的方法,即使没有其他同步也是如此。

对于将频繁更新的目标值,请考虑使用volatile call site 。

使用初始目标方法句柄创建调用站点对象。

使用给定的方法类型创建一个空白的调用站点对象。

返回调用站点的目标方法,其行为类似于

MutableCallSite的普通字段。

更新此调用站点的目标方法,作为普通变量。

对给定数组中的每个调用站点执行同步操作,强制所有其他线程丢弃先前从任何调用站点的目标加载的任何缓存值。

使用给定的方法类型创建一个空白的调用站点对象。

初始目标设置为给定类型的方法句柄,如果调用它将抛出IllegalStateException 。

呼叫站点的类型永久设置为给定类型。

在从引导方法返回CallSite对象之前,或以其他方式调用之前,通常通过调用setTarget为它提供更有用的目标方法。

使用初始目标方法句柄创建调用站点对象。

呼叫站点的类型永久设置为初始目标的类型。

返回调用站点的目标方法,其行为类似于MutableCallSite的普通字段。

getTarget与内存的交互与普通变量的读取相同,例如数组元素或非易失性非最终字段。

特别地,当前线程可以选择从存储器重用先前读取的目标的结果,并且可能无法看到另一个线程对目标的最近更新。

更新此调用站点的目标方法,作为普通变量。

新目标的类型必须与旧目标的类型一致。

与内存的交互与对普通变量的写入相同,例如数组元素或非易失性非最终字段。

特别是,不相关的线程在执行内存读取之前可能无法看到更新的目标。 通过将适当的操作放入引导方法和/或任何给定呼叫站点使用的目标方法,可以创建更强的保证。

对给定数组中的每个调用站点执行同步操作,强制所有其他线程丢弃先前从任何调用站点的目标加载的任何缓存值。

此操作不会撤消已在旧目标值上启动的任何调用。

总体效果是强制每个呼叫站点的目标的所有未来读者接受最近存储的值。 (“最近”是相对于syncAll本身计算的。)相反, syncAll呼叫可能会阻止,直到所有读者都(以某种方式)分解了每个呼叫站点目标的所有先前版本。

为避免竞争条件,通常应在某种互斥条件下执行对setTarget和syncAll调用。 请注意,读取器线程可能会在安装该值的setTarget调用之前(以及确认该值的syncAll之前)观察到更新的目标。 另一方面,读取器线程可能会观察到目标的先前版本,直到syncAll调用返回(以及尝试传达更新版本的setTarget之后)。

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

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

Java内存模型详细信息

就Java内存模型而言,此操作执行同步操作,该操作与当前线程写入易失性变量的效果相当,并且可以访问可能访问受影响的呼叫站点之一的每个其他线程的最终易失性读取。

对于每个呼叫站点S ,以下效果是显而易见的:

创建一个新的volatile变量V ,并由当前线程写入。 根据JMM的定义,此写入是全局同步事件。

正如使用写入事件的线程本地排序一样,当前线程已执行的每个操作都在易失性写入V之前发生。 (在某些实现中,这意味着当前线程执行全局释放操作。)

具体而言,对当前目标S的写入将在易失性写入V之前发生。

对全局同步顺序(以特定于实现的方式)放置对V的易失性写入。

考虑一个任意线程T (当前线程除外)。 如果T在易失性写入V (在全局同步顺序中)之后执行同步操作A ,则因此如果它在目标上执行读取,则需要查看当前目标S或稍后写入该目标。 S 。 (此约束称为“同步顺序一致性”。)

JMM特别允许优化编译器忽略已知无用的变量的读取或写入。 这种省略的读写对前发关系没有影响。 无论这个事实如何,易失性V都不会被省略,即使它的写入值是不确定的并且不使用它的读取值。

因为最后一点,实施行为就像一个挥发性读V被执行T其行动后立即A 。

在T的本地操作顺序中,此读取在将来读取目标S之前发生。

就好像实现任意选择S的目标读取T ,并强制读取V在它之前,从而确保新目标值的通信。

只要遵守Java内存模型的约束,实现可能会延迟syncAll操作的完成,而其他线程(上面的T )继续使用先前值S的目标。 但是,(一如既往)鼓励实现避免活锁,并最终要求所有线程都考虑更新的目标。

讨论:出于性能原因, syncAll不是单个呼叫站点上的虚拟方法,而是适用于一组呼叫站点。 一些实现可能导致用于处理一个或多个同步操作的大的固定开销成本,但是每个附加呼叫站点的增量成本很小。 在任何情况下,该操作可能是昂贵的,因为可能必须以某种方式中断其他线程以使它们注意到更新的目标值。 但是,可以观察到,同步多个站点的单个呼叫具有与许多呼叫相同的正式效果,每个呼叫仅在一个站点上。

实现注意: MutableCallSite简单实现可以使用volatile变量作为可变调用站点的目标。 在这样的实现中, syncAll方法可以是无操作,但它将符合上面记录的JMM行为。

构造方法

构造器

描述

使用初始目标方法句柄创建调用站点对象。

使用给定的方法类型创建一个空白的调用站点对象。变量和类型

方法

描述

返回调用站点的目标方法,其行为类似于

MutableCallSite的普通字段。

void

更新此调用站点的目标方法,作为普通变量。

static void

对给定数组中的每个调用站点执行同步操作,强制所有其他线程丢弃先前从任何调用站点的目标加载的任何缓存值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值