Module java.base
Package java.lang

Class ClassValue<T>


  • public abstract classClassValue<T>extendsObject
    Lazily associate a computed value with (potentially) every type. For example, if a dynamic language needs to construct a message dispatch table for each class encountered at a message send call site, it can use aClassValue to cache information needed to perform the message send quickly, for each class encountered.
    Since:
    1.7
    • Constructor Detail

      • ClassValue

        protected ClassValue()
        Sole constructor. (For invocation by subclass constructors, typically implicit.)
    • Method Detail

      • computeValue

        protected abstract T computeValue​(Class<?> type)
        Computes the given class's derived value for thisClassValue.

        This method will be invoked within the first thread that accesses the value with theget method.

        Normally, this method is invoked at most once per class, but it may be invoked again if there has been a call toremove.

        If this method throws an exception, the corresponding call toget will terminate abnormally with that exception, and no class value will be recorded.

        Parameters:
        type - the type whose class value must be computed
        Returns:
        the newly computed value associated with thisClassValue, for the given class or interface
        See Also:
        get(java.lang.Class<?>),remove(java.lang.Class<?>)
      • get

        public T get​(Class<?> type)
        Returns the value for the given class. If no value has yet been computed, it is obtained by an invocation of thecomputeValue method.

        The actual installation of the value on the class is performed atomically. At that point, if several racing threads have computed values, one is chosen, and returned to all the racing threads.

        Thetype parameter is typically a class, but it may be any type, such as an interface, a primitive type (likeint.class), orvoid.class.

        In the absence ofremove calls, a class value has a simple state diagram: uninitialized and initialized. Whenremove calls are made, the rules for value observation are more complex. See the documentation forremove for more information.

        Parameters:
        type - the type whose class value must be computed or retrieved
        Returns:
        the current value associated with thisClassValue, for the given class or interface
        Throws:
        NullPointerException - if the argument is null
        See Also:
        remove(java.lang.Class<?>),computeValue(java.lang.Class<?>)
      • remove

        public void remove​(Class<?> type)
        Removes the associated value for the given class. If this value is subsequentlyread for the same class, its value will be reinitialized by invoking itscomputeValue method. This may result in an additional invocation of thecomputeValue method for the given class.

        In order to explain the interaction betweenget andremove calls, we must model the state transitions of a class value to take into account the alternation between uninitialized and initialized states. To do this, number these states sequentially from zero, and note that uninitialized (or removed) states are numbered with even numbers, while initialized (or re-initialized) states have odd numbers.

        When a threadT removes a class value in state2N, nothing happens, since the class value is already uninitialized. Otherwise, the state is advanced atomically to2N+1.

        When a threadT queries a class value in state2N, the thread first attempts to initialize the class value to state2N+1 by invokingcomputeValue and installing the resulting value.

        WhenT attempts to install the newly computed value, if the state is still at2N, the class value will be initialized with the computed value, advancing it to state2N+1.

        Otherwise, whether the new state is even or odd,T will discard the newly computed value and retry theget operation.

        Discarding and retrying is an important proviso, since otherwiseT could potentially install a disastrously stale value. For example:

        • T callsCV.get(C) and sees state2N
        • T quickly computes a time-dependent valueV0 and gets ready to install it
        • T is hit by an unlucky paging or scheduling event, and goes to sleep for a long time
        • ...meanwhile,T2 also callsCV.get(C) and sees state2N
        • T2 quickly computes a similar time-dependent valueV1 and installs it onCV.get(C)
        • T2 (or a third thread) then callsCV.remove(C), undoingT2's work
        • the previous actions ofT2 are repeated several times
        • also, the relevant computed values change over time:V1,V2, ...
        • ...meanwhile,T wakes up and attempts to installV0;this must fail
        We can assume in the above scenario thatCV.computeValue uses locks to properly observe the time-dependent states as it computesV1, etc. This does not remove the threat of a stale value, since there is a window of time between the return ofcomputeValue inT and the installation of the new value. No user synchronization is possible during this time.

        Parameters:
        type - the type whose class value must be removed
        Throws:
        NullPointerException - if the argument is null