public abstract class ClassValue<T> extends Object
ClassValue
来缓存为每个遇到的类快速发送消息所需的信息。
protected abstract T computeValue(类<?> type)
ClassValue
。
该方法将在使用get
方法访问该值的第一个线程中调用。
通常,每个类最多调用一次此方法,但如果已经调用remove
,则可以再次调用此方法。
如果这种方法引发异常,对应的调用get
会异常终止,并且不会记录类值。
type
- 必须计算其类值的类型
ClassValue
的新计算值,用于给定的类或接口
get(java.lang.Class<?>)
,
remove(java.lang.Class<?>)
public T get(类<?> type)
computeValue
方法获得。
类的实际安装是以原子方式执行的。 在这一点上,如果几个赛车线程已经计算出值,则选择一个,并返回所有赛车线程。
type
通常是一个类,但它可以是任何类型,如接口,基本类型(如int.class
)或void.class
。
在没有remove
调用的情况下,类值具有简单的状态图:未初始化和初始化。 当进行remove
调用时,值观察规则更为复杂。 请参阅文档remove
以获取更多信息。
type
- 必须计算或检索其类值的类型
ClassValue
的当前值ClassValue,适用于给定的类或接口
NullPointerException
- 如果参数为空
remove(java.lang.Class<?>)
,
computeValue(java.lang.Class<?>)
public void remove(类<?> type)
computeValue
方法。
这可能会导致额外调用给定类的computeValue
方法。
为了解释get
和remove
调用之间的get
,我们必须对类值的状态转换进行建模,以考虑未初始化和初始化状态之间的交替。 为了做到这一点,这些状态从零开始顺序排列,并且注意到未初始化(或去除)状态用偶数编号,而初始化(或重新初始化)状态具有奇数。
当一个线程T
消除状态类值2N
,什么都不会发生,因为类值已经初始化。 否则,国家原子2N+1
。
当线程T
查询状态2N
中的类值时,线程首先尝试通过调用computeValue
并安装结果值将类值2N+1
为状态2N+1
。
当T
尝试安装新计算值时,如果状态仍在2N
,则类值将使用计算值进行初始化,将其推送到状态2N+1
。
否则,新状态是否为偶数,则T
将丢弃新计算值并重试get
操作。
丢弃和重试是一个重要的条件,因为否则T
可能会安装一个灾难性的陈旧的值。 例如:
T
致电CV.get(C)
,看到状态2N
T
快速计算一个时间依赖值V0
并准备安装它 T
被不幸的寻呼或调度事件击中,并长时间睡觉 T2
也叫CV.get(C)
,看到状态2N
T2
快速计算类似的时间依赖值V1
并安装在CV.get(C)
T2
(或第三个线程)然后调用CV.remove(C)
,撤消T2
的工作 T2
的以前的动作重复了几次 V1
, V2
,... T
醒来,试图安装V0
; 这必须失败 CV.computeValue
使用锁来适当地观察时间依赖状态,因为它计算V1
等。这并不能消除陈旧价值的威胁,因为在computeValue
之间有一个时间窗口T
和安装的新值。
在此期间无法进行用户同步。
type
- 必须删除其类值的类型
NullPointerException
- if the argument is null