- java.lang.Object
-
- java.lang.ClassValue<T>
-
public abstract class ClassValue<T>extends Object
懒惰地将计算值与(可能)每种类型相关联。 例如,如果动态语言需要为消息发送调用站点遇到的每个类构造消息调度表,则可以使用ClassValue
来缓存为遇到的每个类快速执行消息发送所需的信息。- 从以下版本开始:
- 1.7
-
-
构造方法摘要
构造方法 变量 构造器 描述 protected
ClassValue()
唯一的构造函数。
-
-
-
方法详细信息
-
computeValue
protected abstract T computeValue(类<?> type)
计算此ClassValue
的给定类的派生值。将使用
get
方法在第一个访问该值的线程中调用此方法。通常,每个类最多调用一次此方法,但如果调用
remove
,则可以再次调用此方法。如果此方法抛出异常,则对该异常的相应调用
get
将异常终止,并且不会记录任何类值。- 参数
-
type
- 必须计算其类值的类型 - 结果
- 对于给定的类或接口,与此
ClassValue
关联的新计算值 - 另请参见:
-
get(java.lang.Class<?>)
,remove(java.lang.Class<?>)
-
get
public T get(类<?> type)
返回给定类的值。 如果尚未计算任何值,则通过调用computeValue
方法获得该值 。类的实际安装是以原子方式执行的。 此时,如果几个赛车线程具有计算值,则选择一个,并返回到所有赛车线程。
type
参数通常是一个类,但它可以是任何类型,例如接口,基本类型(如int.class
)或void.class
。在没有
remove
调用的情况下,类值具有简单的状态图:未初始化和初始化。 当进行remove
调用时,值观察的规则更复杂。 有关更多信息,请参阅remove
的文档。- 参数
-
type
- 必须计算或检索其类值的类型 - 结果
- 对于给定的类或接口,与此
ClassValue
关联的当前值 - 异常
-
NullPointerException
- 如果参数为null - 另请参见:
-
remove(java.lang.Class<?>)
,computeValue(java.lang.Class<?>)
-
remove
public void remove(类<?> type)
删除给定类的关联值。 如果该值随后是同一类的read ,则将通过调用其computeValue
方法重新初始化其值。 这可能导致为给定类额外调用computeValue
方法。为了解释
get
和remove
调用之间的交互,我们必须对类值的状态转换进行建模,以考虑未初始化状态和初始化状态之间的交替。 为此,请从零开始按顺序对这些状态进行编号,并注意未初始化(或已移除)状态用偶数编号,而初始化(或重新初始化)状态具有奇数。当一个线程
T
消除状态类值2N
,什么都不会发生,因为类值已经初始化。 否则,状态以原子方式提前到2N+1
。当线程
T
查询状态2N
的类值时,线程首先尝试通过调用computeValue
并安装结果值来将类值初始化为状态2N+1
。当
T
尝试安装新计算的值时,如果状态仍为2N
,则将使用计算值初始化类值,将其提前到状态2N+1
。否则,无论新状态是偶数还是奇数,
T
将丢弃新计算的值get
试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
-
-
-