Package tenapull.sync

Class InstancesTracker<K,​I>

java.lang.Object
tenapull.sync.InstancesTracker<K,​I>
Type Parameters:
K - the type parameter
I - the type parameter

public class InstancesTracker<K,​I>
extends java.lang.Object
Synchronizes and maps unique instances to a unique "key" (typically a String, Number, or Hash). Instances are held as weak references via a WeakHashMap which is synchronized via ReadWriteLock.

NOTE: The implementation of this class inverts keys and value. It is a little counter-intuitive that the instance is the key of the actual WeakHashMap and the key is the value. But this is needed for the "Weak" reference to work correctly, and allow garbage collection of unused instances.

In a sense, both the keys and values "keys" for each other, but only the instance is a weak reference that can be garbage-collected, which is why it must occupy the formal 'key' position in the WeakHashMap. However, for users of InstancesTracker, the instances are considered to be the "values", and the accessor strong references (typically strings) are considered to be the "keys". The strongly-referenced "keys" may have more than one key per instance, but each key may refer to only one instance, like a normal map.

The "put" method is ONLY for adding additional keys to a pre-existing instance because an instance should not be constructed without first obtaining a CreateLock for the initial key. There are several methods for this. 1) getOrConstruct(K key). A default construct lambda should be provided with the InstancesTracker constructor. The construct lambda will be called with appropriate locks by the getOrConstruct method.

2) getOrConstructWith(K key, Lambda1/2) like getOrConstruct but with a custom construction lambda instead of the default lambda.

3) constructWith(K key, Lambda1/2) Construct with a custom lambda, the returned instance will override any previously existing instance associated with the given key.

Type parameters:

K -- Key -- the string, integer, hash or other value used to access the instances. There is a strong reference to these values

I -- Instances -- the type of the instances being tracked. These are weak references so may be garbage collected if no strong references remain to the instance, in which case the strong reference to the key will also be destroyed here (though there may be strong references elsewhere that prevent it from being garbage-collected)

  • Nested Class Summary

    Nested Classes 
    Modifier and Type Class Description
    static class  InstancesTracker.AlreadyFinalized
    Thrown when an unexpected state is reached during create lock finalization.
    static class  InstancesTracker.CreateLockException
    Thrown when a construct-lambda holding a create lock tries to obtain another create lock.
    static class  InstancesTracker.InstancesTrackerException
    Abstract supertype of all specialized exceptions thrown by InstanceTracker
    static interface  InstancesTracker.KeyFinalizer<K extends InstancesTracker.KeyFinalizer<K,​I>,​I>
    The interface Key finalizer, which may be implemented by custom keys.
    class  InstancesTracker.KeySet
    NOT COMPLETED.
    static class  InstancesTracker.NullInstanceArgument
    Thrown when a null instance is passed to put or putWithLock
    static class  InstancesTracker.NullKeyArgument
    Thrown when a null key is passed to a construct method
    static class  InstancesTracker.TrackerDiscontinuedException
    Thrown if the instances tracker was discontinued because it was replaced by another tracker with the same key and argument types and type params
    static class  InstancesTracker.UnrecognizedInstance
    Thrown when an instance is passed to a method requiring an instance argument that was not constructed under the lock of the given instancesTracker
  • Field Summary

    Fields 
    Modifier and Type Field Description
    static double BILLION
    The constant BILLION, used for converting between nanoseconds and seconds
    static long MILLION
    The constant MILLION used for converting between nanoseconds and milliseconds
  • Constructor Summary

    Constructors 
    Constructor Description
    InstancesTracker​(java.lang.Class<K> keyType, java.lang.Class<I> instancesType, Lambda1<K,​I> constructionLambda)
    Instantiates a new Instances tracker of the given key and value types
    InstancesTracker​(Type<K> keyType, Type<I> instType, Lambda1<K,​I> constructionLambda)
    Instantiates a new Instances tracker.
  • Method Summary

    Modifier and Type Method Description
    java.util.Set<K> clearKeysFor​(I instance)
    Clears all keys associated with the provided instance, and returns them
    I construct​(K key)
    Forces construction of an instance associated with the provided key using the default construct lambda provided at the InstancesTracker's constructor, overriding any previously existing instance associated with the key.
    I constructWith​(K key, Lambda1<K,​I> customLambda)
    Forces construction of an instance associated with the provided key using the provided construct lambda, overriding any previously existing instance associated with the key.
    I get​(K key)
    Get the instance associated with the provided key
    java.util.List<I> get​(Lambda1<I,​java.lang.Boolean> filter)
    Applies a filter lambda to the entire set of instances, and returns a list of the instances for which the lambda returns true.
    java.util.List<I> get​(Lambda1<I,​java.lang.Boolean> filter, int limit)
    Applies a filter lambda to the entire set of instances, and returns a list of the instances for which the lambda returns true, stopping after the providing limit is reached.
    Lambda1<K,​I> getConstruct()
    Gets the default construct lambda, provided at the construction of this instances tracker
    java.util.Set<I> getInstances()
    Gets the set of all instances constructed under the lock of this instancesTracker that haven't been GC'd
    java.util.Set<K> getKeysFor​(I instance)
    Gets all keys associated with the provided instance
    I getOrConstruct​(K key)
    Gets the instance matching the provided key, or constructs it with the default construct-lambda provided in the InstancesTracker's constructor.
    I getOrConstructWith​(K key, Lambda1<K,​I> customLambda)
    Gets the instance matching the provided key, or constructs it with the provided custom construct-lambda, Note that even if the construct lambda runs, it is possible that a different instance will be returned by this method, if another thread overrides the instance associated with the key while the construct lambda is running.
    static RecursiveMap<java.lang.Thread> getThreadBlockingMap()
    Iterates over all existing instances trackers and their create locks, and generates a recursive map of which threads are blocking which other threads.
    static RecursiveMap<java.lang.Thread> getThreadBlockingMap​(RecursiveMap<java.lang.Thread> preFilled)
    Iterates over all active instances trackers and their create locks, and generates a recursive map of which threads are blocking which other threads.
    java.util.Set<K> keySet()
    Get the set of keys.
    I put​(K key, I instance)
    Puts a new key-instance association for a previously constructed instances, or adds an extra key for an instance which is currently under construction.
    I remove​(K key)
    Remove the key from the instances tracker.
    static boolean runFinalizer​(long maxTimeNs)
    Runs a single iteration of finalization for all InstancesTracker needing it, with the provided maximum timeout before quitting.
    int size()
    The number of instances that have been constructed and which still exist (aka, haven't been GC'd).

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • BILLION

      public static final double BILLION
      The constant BILLION, used for converting between nanoseconds and seconds
      See Also:
      Constant Field Values
    • MILLION

      public static final long MILLION
      The constant MILLION used for converting between nanoseconds and milliseconds
      See Also:
      Constant Field Values
  • Constructor Details

    • InstancesTracker

      public InstancesTracker​(java.lang.Class<K> keyType, java.lang.Class<I> instancesType, Lambda1<K,​I> constructionLambda) throws java.lang.NullPointerException
      Instantiates a new Instances tracker of the given key and value types
      Parameters:
      keyType - the key type
      instancesType - the instances type
      constructionLambda - the default construction lambda (may be null)
      Throws:
      java.lang.NullPointerException - if the keyType or instancesType are null.
    • InstancesTracker

      public InstancesTracker​(Type<K> keyType, Type<I> instType, Lambda1<K,​I> constructionLambda) throws java.lang.NullPointerException
      Instantiates a new Instances tracker.
      Parameters:
      keyType - the key type
      instType - the inst type
      constructionLambda - the construction lambda (may be null)
      Throws:
      java.lang.NullPointerException - if the keyType or instancesType are null
  • Method Details

    • keySet

      public java.util.Set<K> keySet()
      Get the set of keys. IMPORTANT: the implementation of the keySet inner class was never completed. Use extreme caution if trying to use it, as it may not be synchronized with the actual keys in use, and may have undefined/exception-prone behavior in certain cases.
      Returns:
      the set
    • size

      public int size()
      The number of instances that have been constructed and which still exist (aka, haven't been GC'd). Note that this may be an expensive operation, because it requires waiting for construction to finish on all existing create locks, and then finalizing all of them.
      Returns:
      the size
    • get

      public I get​(K key)
      Get the instance associated with the provided key
      Parameters:
      key - the key
      Returns:
      the instance associated with the provided key
    • get

      public java.util.List<I> get​(Lambda1<I,​java.lang.Boolean> filter)
      Applies a filter lambda to the entire set of instances, and returns a list of the instances for which the lambda returns true. Note that this may be an expensive operation, because it requires waiting for construction to finish on all existing create locks, and then finalizing all of them before the comparisons can be conducted.
      Parameters:
      filter - the filter
      Returns:
      the list of matching instances
    • get

      public java.util.List<I> get​(Lambda1<I,​java.lang.Boolean> filter, int limit)
      Applies a filter lambda to the entire set of instances, and returns a list of the instances for which the lambda returns true, stopping after the providing limit is reached. If limit <= 0 then the iteration will not stop until all instances have been checked. Note that this may be an expensive operation, because it requires waiting for construction to finish on all existing create locks, and then finalizing all of them before the comparisons can be conducted.
      Parameters:
      filter - the filter
      limit - the number of matched instances at which to stop checking, or <= 0 to check every instance
      Returns:
      the list of matching instances
    • getOrConstruct

      Gets the instance matching the provided key, or constructs it with the default construct-lambda provided in the InstancesTracker's constructor. Note that even if the construct lambda runs, it is possible that a different instance will be returned by this method, if another thread overrides the instance associated with the key while the construct lambda is running. Also note that getOrConstruct is NOT considered a force-overriding method call, and that the lambda is not guaranteed to run, though IF it does run it will only run before this method returns. To force-override a key's associated instance, use construct or constructWith
      Parameters:
      key - the key
      Returns:
      the instance associated with the key
      Throws:
      InstancesTracker.InstancesTrackerException - if the key is null
      InstancesTracker.CreateLockException - if this method is being called from within the context of another construct lambda holding a create lock from this instancesTracker. To add a key-instance pair within such a context, use the put method
    • constructWith

      public I constructWith​(K key, Lambda1<K,​I> customLambda) throws InstancesTracker.InstancesTrackerException, java.lang.NullPointerException, InstancesTracker.CreateLockException
      Forces construction of an instance associated with the provided key using the provided construct lambda, overriding any previously existing instance associated with the key. Note that even though the construct lambda is guaranteed to run before this method returns, it is still possible that a different instance will be returned by this method, if another thread also overrides the instance associated with the key while the construct lambda is running.
      Parameters:
      key - the key
      customLambda - the custom construct lambda
      Returns:
      the
      Throws:
      InstancesTracker.InstancesTrackerException - if the key is null
      java.lang.NullPointerException - if the construct lambda is null
      InstancesTracker.CreateLockException - if this method is being called from within the context of another construct lambda holding a create lock from this instancesTracker. To add a key-instance pair within such a context, use the put method
    • getOrConstructWith

      public I getOrConstructWith​(K key, Lambda1<K,​I> customLambda) throws InstancesTracker.InstancesTrackerException, java.lang.NullPointerException, InstancesTracker.CreateLockException
      Gets the instance matching the provided key, or constructs it with the provided custom construct-lambda, Note that even if the construct lambda runs, it is possible that a different instance will be returned by this method, if another thread overrides the instance associated with the key while the construct lambda is running. Also note that getOrConstruct is NOT considered a force-overriding method call, and that the lambda is not guaranteed to run, though IF it does run it will only run before this method returns. To force-override a key's associated instance, use construct or constructWith
      Parameters:
      key - the key
      Returns:
      the instance associated with the key
      Throws:
      InstancesTracker.InstancesTrackerException - if the key is null
      InstancesTracker.CreateLockException - if this method is being called from within the context of another construct lambda holding a create lock from this instancesTracker. To add a key-instance pair within such a context, use the put method
      java.lang.NullPointerException
    • construct

      Forces construction of an instance associated with the provided key using the default construct lambda provided at the InstancesTracker's constructor, overriding any previously existing instance associated with the key. Note that even though the default construct lambda is guaranteed to run before this method returns, it is still possible that a different instance will be returned by this method, if another thread also overrides the instance associated with the key while the lambda is running.
      Parameters:
      key - the key
      Returns:
      the instance associated with the key
      Throws:
      InstancesTracker.InstancesTrackerException - if the key is null
      InstancesTracker.CreateLockException - if this method is being called from within the context of another construct lambda holding a create lock from this instancesTracker. To add a key-instance pair within such a context, use the put method
    • remove

      public I remove​(K key)
      Remove the key from the instances tracker. Note that although the instance the key referenced may no longer have any key associated with it, the instance will still be held as a weak reference in the InstancesTracker, and (if an external reference to it exists) may have a new key associated with it using the put method.
      Parameters:
      key - the key to remove
      Returns:
      the instance that was associated with the key
    • getKeysFor

      public java.util.Set<K> getKeysFor​(I instance) throws InstancesTracker.UnrecognizedInstance
      Gets all keys associated with the provided instance
      Parameters:
      instance - the instance
      Returns:
      the set of keys associated with the provided instance
      Throws:
      InstancesTracker.UnrecognizedInstance - if the instance is not recognized as an instance constructed under the lock of this instancesTracker.
    • clearKeysFor

      public java.util.Set<K> clearKeysFor​(I instance) throws InstancesTracker.UnrecognizedInstance
      Clears all keys associated with the provided instance, and returns them
      Parameters:
      instance - the instance
      Returns:
      the set of keys previously associated with the instance
      Throws:
      InstancesTracker.UnrecognizedInstance - if the instance is not recognized as an instance constructed under the lock of this instancesTracker.
    • getInstances

      public java.util.Set<I> getInstances()
      Gets the set of all instances constructed under the lock of this instancesTracker that haven't been GC'd
      Returns:
      the instances
    • put

      public I put​(K key, I instance) throws InstancesTracker.UnrecognizedInstance
      Puts a new key-instance association for a previously constructed instances, or adds an extra key for an instance which is currently under construction.
      Parameters:
      key - the key
      instance - the instance
      Returns:
      the
      Throws:
      InstancesTracker.UnrecognizedInstance - if the instance is not recognized as an instance constructed under the lock of this instancesTracker.
    • getConstruct

      public Lambda1<K,​I> getConstruct()
      Gets the default construct lambda, provided at the construction of this instances tracker
      Returns:
      the default construct lambda
    • getThreadBlockingMap

      public static RecursiveMap<java.lang.Thread> getThreadBlockingMap()
      Iterates over all existing instances trackers and their create locks, and generates a recursive map of which threads are blocking which other threads. This method begins with the threadBlockingMap returned from ReadWriteLock
      Returns:
      the map of which threads are blocking which other threads
    • getThreadBlockingMap

      public static RecursiveMap<java.lang.Thread> getThreadBlockingMap​(RecursiveMap<java.lang.Thread> preFilled)
      Iterates over all active instances trackers and their create locks, and generates a recursive map of which threads are blocking which other threads. The caller may include a pre-filled Recursive map (e.g. from ReadWriteLock.getThreadBlockingMap) that will be further populated, or an empty RecursiveMap to just see the blocks from InstancesTrackers
      Parameters:
      preFilled - the pre filled recursive map of thread blocks
      Returns:
      the thread blocking map8\
    • runFinalizer

      public static boolean runFinalizer​(long maxTimeNs)
      Runs a single iteration of finalization for all InstancesTracker needing it, with the provided maximum timeout before quitting. This method is used by the finalizer thread, and can also be invoked by other threads with nothing else to do (e.g. by JobFactory)
      Parameters:
      maxTimeNs - the max time in nanoseconds before quitting
      Returns:
      true if there was finalizing that needed to be done, false if there was nothing to do