Class InstancesTracker<K,I>
- Type Parameters:
K
- the type parameterI
- the type parameter
public class InstancesTracker<K,I>
extends java.lang.Object
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 InstanceTrackerstatic 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 putWithLockstatic class
InstancesTracker.NullKeyArgument
Thrown when a null key is passed to a construct methodstatic 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 paramsstatic 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
-
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 typesInstancesTracker(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 themI
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 keyjava.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 trackerjava.util.Set<I>
getInstances()
Gets the set of all instances constructed under the lock of this instancesTracker that haven't been GC'djava.util.Set<K>
getKeysFor(I instance)
Gets all keys associated with the provided instanceI
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).
-
Field Details
-
BILLION
public static final double BILLIONThe constant BILLION, used for converting between nanoseconds and seconds- See Also:
- Constant Field Values
-
MILLION
public static final long MILLIONThe 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.NullPointerExceptionInstantiates a new Instances tracker of the given key and value types- Parameters:
keyType
- the key typeinstancesType
- the instances typeconstructionLambda
- 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.NullPointerExceptionInstantiates a new Instances tracker.- Parameters:
keyType
- the key typeinstType
- the inst typeconstructionLambda
- the construction lambda (may be null)- Throws:
java.lang.NullPointerException
- if the keyType or instancesType are null
-
-
Method Details
-
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
Get the instance associated with the provided key- Parameters:
key
- the key- Returns:
- the instance associated with the provided key
-
get
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
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 filterlimit
- the number of matched instances at which to stop checking, or <= 0 to check every instance- Returns:
- the list of matching instances
-
getOrConstruct
public I getOrConstruct(K key) throws InstancesTracker.InstancesTrackerException, InstancesTracker.CreateLockExceptionGets 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 nullInstancesTracker.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.CreateLockExceptionForces 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 keycustomLambda
- the custom construct lambda- Returns:
- the
- Throws:
InstancesTracker.InstancesTrackerException
- if the key is nulljava.lang.NullPointerException
- if the construct lambda is nullInstancesTracker.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.CreateLockExceptionGets 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 nullInstancesTracker.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 methodjava.lang.NullPointerException
-
construct
public I construct(K key) throws InstancesTracker.InstancesTrackerException, InstancesTracker.CreateLockExceptionForces 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 nullInstancesTracker.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
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
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
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
Gets the set of all instances constructed under the lock of this instancesTracker that haven't been GC'd- Returns:
- the instances
-
put
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 keyinstance
- the instance- Returns:
- the
- Throws:
InstancesTracker.UnrecognizedInstance
- if the instance is not recognized as an instance constructed under the lock of this instancesTracker.
-
getConstruct
Gets the default construct lambda, provided at the construction of this instances tracker- Returns:
- the default construct lambda
-
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
-