- Type Parameters:
T- The type ofPoolablemanaged by this pool.
- All Implemented Interfaces:
ManagedPool,Pool<T>,PoolTap<T>
Pool implementation that consists of
a queues of Poolable instances, the access to which is made faster with
clever use of ThreadLocals.
Object allocation always happens in a dedicated thread, off-loading the cost of allocating the pooled objects. This leads to reduced deviation in the times it takes claim method to complete, provided the pool is not depleted.
BlazePool optimises for the case where the same threads need to claim and release objects over and over again. On the other hand, if the releasing thread tends to differ from the claiming thread, then the major optimisation in BlazePool is defeated, and performance regresses to a slow-path that is limited by contention on a blocking queue.
- Author:
- Chris Vest
-
Constructor Summary
ConstructorsConstructorDescriptionBlazePool(PoolBuilderImpl<T> builder, AllocationProcess factory) Construct a new BlazePool instance based on the givenPoolBuilder. -
Method Summary
Modifier and TypeMethodDescriptionClaim the exclusive rights until released, to an object in the pool.longReturn the number of objects the pool has allocated since it was created.doublegetAllocationFailureLatencyPercentile(double percentile) Get the approximate latency value, in milliseconds, for failed allocation latencies within the given percentile/quantile of what has been recorded so far.doublegetAllocationLatencyPercentile(double percentile) Get the approximate Poolable object allocation latency value, in milliseconds, of the given percentile/quantile of the values recorded so far.longGet the approximate number of currently allocated objects.longGet the approximate number of objects currently in use.doublegetDeallocationLatencyPercentile(double percentile) Get the approximate latency value, in milliseconds, for deallocation latencies within the given percentile/quantile of what has been recorded so far.longReturn the number of allocations that has failed, either because the allocator threw an exception or because it returned null, since the pool was created.longIf the pool is capable of precise object leak detection, this method will return the number of object leaks that have been detected, and prevented, since the pool was created.Get theManagedPoolinstance that represents this pool.doublegetObjectLifetimePercentile(double percentile) Get the approximate object lifetime, in milliseconds, for the given percentile/quantile.doublegetReallocationFailureLatencyPercentile(double percentile) Get the approximate latency value, in milliseconds, for failed reallocation latencies within the given percentile/quantile of what has been recorded so far.doublegetReallocationLatencyPercentile(double percentile) Get the approximate latency value, in milliseconds, for reallocation latencies within the given percentile/quantile of what has been recorded so far.Get aPoolTapthat only support access by one thread at a time.longGet the currently configured target size of the pool.Get a thread-safePoolTapimplementation for this pool, which can be freely shared among multiple threads.Get a thread-safePoolTapimplementation for this pool, which can be freely shared among multiple threads, including virtual threads.booleanReturnstrueif the shutdown process has been started on this pool,falseotherwise.voidsetTargetSize(long size) Set the target size for this pool.shutdown()Initiate the shutdown process on this pool, and return aCompletioninstance representing the shutdown procedure.switchAllocator(Allocator<T> replacementAllocator) Initiate a switch from the current allocator to the given allocator.tryClaim()Returns an object from the pool if the pool contains at least one valid object, otherwise returnsnull.
-
Constructor Details
-
BlazePool
Construct a new BlazePool instance based on the givenPoolBuilder.- Parameters:
builder- The pool configuration to use.factory- The allocation process that builds theAllocationControllerused by this pool.
-
-
Method Details
-
claim
Description copied from interface:PoolTapClaim the exclusive rights until released, to an object in the pool. Possibly waiting up to the specified amount of time, as given by the providedTimeoutinstance, for one to become available if the pool has been depleted. If the timeout elapses before an object can be claimed, thennullis returned instead. The timeout will be honoured even if the Allocatorsallocatemethods blocks forever. If the given timeout has a zero or negative value, then the method will not wait.If the current thread has already one or more objects currently claimed, then a distinct object will be returned, if one is or becomes available. This means that it is possible for a single thread to deplete the pool, if it so desires. However, doing so is inherently deadlock prone, so avoid claiming more than one object at a time per thread, if at all possible.
This method may throw a PoolException if the pool have trouble allocating objects. That is, if its assigned Allocator throws exceptions from its allocate method, or returns
null.An
InterruptedExceptionwill be thrown if the thread has its interrupted flag set upon entry to this method, or is interrupted while waiting. The interrupted flag on the thread will be cleared after this, as per the general contract of interruptible methods.If the pool has been shut down, then an
IllegalStateExceptionwill be thrown when this method is called. Likewise, if we are waiting for an object to become available, and someone shuts the pool down.Here's an example code snippet, where an object is claimed, printed to
System.out, and then released back to the pool:Poolable obj = pool.claim(TIMEOUT); if (obj != null) { try { System.out.println(obj); } finally { obj.release(); } }Memory effects:
- The
releaseof an object happens-before any subsequent claim ordeallocationof that object, and, - The
allocationof an object happens-before any claim of that object.
- Specified by:
claimin interfacePoolTap<T extends Poolable>- Parameters:
timeout- The timeout of the maximum permitted time-slice to wait for an object to become available. A timeout with a value of zero or less, means that the call will do no waiting, preferring instead to return early if no objects are available.- Returns:
- An object of the Poolable subtype T to which the exclusive rights
have been claimed, or
nullif the timeout period elapsed before an object became available. - Throws:
PoolException- If an object allocation failed because the Allocator threw an exception from its allocate method, or returnednull, or theexpiration checkthrew an exception.InterruptedException- if the current thread isinterruptedupon entry, or becomes interrupted while waiting.
- The
-
tryClaim
Description copied from interface:PoolTapReturns an object from the pool if the pool contains at least one valid object, otherwise returnsnull. This method will first try to return cached object if available. If no locally cached object is found, it will go through objects in the pool and return the first ready to claim object. If all the objects in the pool is drained, thennullwill be returned.- Specified by:
tryClaimin interfacePoolTap<T extends Poolable>- Returns:
- an object from the pool if the pool contains at least one valid object,
otherwise returns
null. - Throws:
PoolException- If an object allocation failed because the Allocator threw an exception from its allocate method, or returnednull, or theexpiration checkthrew an exception.
-
shutdown
Description copied from interface:PoolInitiate the shutdown process on this pool, and return aCompletioninstance representing the shutdown procedure.The shutdown process is asynchronous, and the shutdown method is guaranteed to not wait for any claimed
Poolablesto be released.The shutdown process cannot complete before all Poolables are released back into the pool and
deallocated, and all internal resources (such as threads, for instance) have been released as well. Only when all of these things have been taken care of, does the await methods of the Completion return.Once the shutdown process has been initiated, that is, as soon as this method is called, the pool can no longer be used and all calls to
PoolTap.claim(Timeout)will throw anIllegalStateException. Threads that are already waiting for objects in the claim method, will also wake up and receive anIllegalStateException.All objects that are already claimed when this method is called, will continue to function until they are
released.The shutdown process is guaranteed to never deallocate objects that are currently claimed. Their deallocation will wait until they are released.
- Specified by:
shutdownin interfacePool<T extends Poolable>- Returns:
- A
Completioninstance that represents the shutdown process.
-
switchAllocator
Description copied from interface:PoolInitiate a switch from the current allocator to the given allocator.This will cause all current objects to be deallocated by the old allocator, and reallocated by the new allocator. The objects will be replaced one at a time.
The returned completion will complete when all objects have been replaced, or if the pool shuts down. If another switch is initiated before the completion of a prior switch, then the prior completion will complete when there are no more objects left from the allocator that was current at the time the prior completion was initiated.
Direct pools, created with the
Pool.of(Object[])method, do not support switching allocators, and will instead throw anUnsupportedOperationExceptionfrom this method.If this pool has already been shut down, then this method immediately returns a completed completion instance.
- Specified by:
switchAllocatorin interfacePool<T extends Poolable>- Parameters:
replacementAllocator- The new allocator.- Returns:
- A
Completioninstance that represents the switch process.
-
setTargetSize
public void setTargetSize(long size) Description copied from interface:PoolSet the target size for this pool. The pool will strive to keep this many objects allocated at any one time.If the new target size is greater than the old one, the pool will allocate more objects until it reaches the target size. If, on the other hand, the new target size is less than the old one, the pool will deallocate more and allocate less, until the new target size is reached.
No guarantees are made about when the pool actually reaches the target size. In fact, it may never happen as the target size can be changed as often as one sees fit.
Pools that do not support a size less than 0 (which would deviate from the standard configuration space) will throw an
IllegalArgumentExceptionif passed -1 or less.Pools that do not support online resizing will throw an
UnsupportedOperationException.- Specified by:
setTargetSizein interfaceManagedPool- Specified by:
setTargetSizein interfacePool<T extends Poolable>- Parameters:
size- The new target size of the pool.- See Also:
-
getTargetSize
public long getTargetSize()Description copied from interface:PoolGet the currently configured target size of the pool. Note that this is not the number of objects currently allocated by the pool - only the number of allocations the pool strives to keep alive.- Specified by:
getTargetSizein interfaceManagedPool- Specified by:
getTargetSizein interfacePool<T extends Poolable>- Returns:
- The current target size of this pool.
- See Also:
-
getManagedPool
Description copied from interface:PoolGet theManagedPoolinstance that represents this pool.- Specified by:
getManagedPoolin interfacePool<T extends Poolable>- Returns:
- The
ManagedPoolinstance for this pool.
-
getThreadSafeTap
Description copied from interface:PoolGet a thread-safePoolTapimplementation for this pool, which can be freely shared among multiple threads.If the pool tap will be accessed by virtual threads, then
Pool.getVirtualThreadSafeTap()should be used instead.- Specified by:
getThreadSafeTapin interfacePool<T extends Poolable>- Returns:
- A thread-safe
PoolTap.
-
getVirtualThreadSafeTap
Description copied from interface:PoolGet a thread-safePoolTapimplementation for this pool, which can be freely shared among multiple threads, including virtual threads.The implementation of this
PoolTapavoids the use ofThreadLocalvariables, locking mechanisms, and other API calls that are poorly supported by, or disruptive to, virtual threads.- Specified by:
getVirtualThreadSafeTapin interfacePool<T extends Poolable>- Returns:
- A thread-safe
PoolTap.
-
getSingleThreadedTap
Description copied from interface:PoolGet aPoolTapthat only support access by one thread at a time. In other words, wherePoolTap.claim(Timeout)cannot be called concurrently in multiple threads *on the same tap*.The pool itself will still be thread-safe, but each thread that wishes to access the pool via a thread-local tap, must have their own tap instance.
It is a use error to access these pool taps concurrently from multiple threads, or to transfer them from one thread to another without safe publication.
- Specified by:
getSingleThreadedTapin interfacePool<T extends Poolable>- Returns:
- A thread-local
PoolTap.
-
getAllocationCount
public long getAllocationCount()Description copied from interface:ManagedPoolReturn the number of objects the pool has allocated since it was created.- Specified by:
getAllocationCountin interfaceManagedPool- Returns:
- The number of Poolable objects ever created by this pool.
-
getFailedAllocationCount
public long getFailedAllocationCount()Description copied from interface:ManagedPoolReturn the number of allocations that has failed, either because the allocator threw an exception or because it returned null, since the pool was created.- Specified by:
getFailedAllocationCountin interfaceManagedPool- Returns:
- The number of allocations that have failed for one reason or another.
-
isShutDown
public boolean isShutDown()Description copied from interface:ManagedPoolReturnstrueif the shutdown process has been started on this pool,falseotherwise. This method does not reveal whether the shutdown process has completed.- Specified by:
isShutDownin interfaceManagedPool- Returns:
trueifPool.shutdown()has been called on this pool.
-
getObjectLifetimePercentile
public double getObjectLifetimePercentile(double percentile) Description copied from interface:ManagedPoolGet the approximate object lifetime, in milliseconds, for the given percentile/quantile.- Specified by:
getObjectLifetimePercentilein interfaceManagedPool- Parameters:
percentile- The percentile to get, as a decimal, e.g. a number between 0.0 and 1.0.- Returns:
- The approximate object lifetime in milliseconds, for the given
percentile, or Double.NaN if no
MetricsRecorderhas been configured for the pool. - See Also:
-
getAllocationLatencyPercentile
public double getAllocationLatencyPercentile(double percentile) Description copied from interface:ManagedPoolGet the approximate Poolable object allocation latency value, in milliseconds, of the given percentile/quantile of the values recorded so far.- Specified by:
getAllocationLatencyPercentilein interfaceManagedPool- Parameters:
percentile- The percentile to get, as a decimal, e.g. a number between 0.0 and 1.0.- Returns:
- The approximate latency for allocations in milliseconds, for the
given percentile, or Double.NaN if no
MetricsRecorderhas been configured for the pool. - See Also:
-
getAllocationFailureLatencyPercentile
public double getAllocationFailureLatencyPercentile(double percentile) Description copied from interface:ManagedPoolGet the approximate latency value, in milliseconds, for failed allocation latencies within the given percentile/quantile of what has been recorded so far.- Specified by:
getAllocationFailureLatencyPercentilein interfaceManagedPool- Parameters:
percentile- The percentile to get, as a decimal, e.g. a number between 0.0 and 1.0.- Returns:
- The approximate latency for failed allocations in milliseconds,
for the given percentile, or Double.NaN if no
MetricsRecorderhas been configured for the pool. - See Also:
-
getReallocationLatencyPercentile
public double getReallocationLatencyPercentile(double percentile) Description copied from interface:ManagedPoolGet the approximate latency value, in milliseconds, for reallocation latencies within the given percentile/quantile of what has been recorded so far.- Specified by:
getReallocationLatencyPercentilein interfaceManagedPool- Parameters:
percentile- The percentile to get, as a decimal, e.g. a number between 0.0 and 1.0.- Returns:
- The approximate latency for reallocations in milliseconds, for the
given percentile, or Double.NaN if no
MetricsRecorderhas been configured for the pool. - See Also:
-
getReallocationFailureLatencyPercentile
public double getReallocationFailureLatencyPercentile(double percentile) Description copied from interface:ManagedPoolGet the approximate latency value, in milliseconds, for failed reallocation latencies within the given percentile/quantile of what has been recorded so far.- Specified by:
getReallocationFailureLatencyPercentilein interfaceManagedPool- Parameters:
percentile- The percentile to get, as a decimal, e.g. a number between 0.0 and 1.0.- Returns:
- The approximate latency for failed reallocations in milliseconds,
for the given percentile, or Double.NaN if no
MetricsRecorderhas been configured for the pool. - See Also:
-
getDeallocationLatencyPercentile
public double getDeallocationLatencyPercentile(double percentile) Description copied from interface:ManagedPoolGet the approximate latency value, in milliseconds, for deallocation latencies within the given percentile/quantile of what has been recorded so far.- Specified by:
getDeallocationLatencyPercentilein interfaceManagedPool- Parameters:
percentile- The percentile to get, as a decimal, e.g. a number between 0.0 and 1.0.- Returns:
- The approximate latency for deallocations, regardless of whether
the throw exceptions or not, in milliseconds for the given percentile, or
Double.NaN if no
MetricsRecorderhas been configured for the pool. - See Also:
-
getLeakedObjectsCount
public long getLeakedObjectsCount()Description copied from interface:ManagedPoolIf the pool is capable of precise object leak detection, this method will return the number of object leaks that have been detected, and prevented, since the pool was created. If the pool does not support precise object leak detection, then this method returns -1.There are two kinds of leaks: One where the application forgets to release an object back to the pool, but keeps a strong reference to the object, and another where the application not only forgets to release the object, but also looses the reference to the object, making it eligible for garbage collection. The precise leak detector will only count leaks of the latter kind, where the leaked object has been garbage collected.
- Specified by:
getLeakedObjectsCountin interfaceManagedPool- Returns:
- The number of objects leaked from the users of this pool, since the pool was created, or -1 if the pool does not implement precise leak detection.
-
getCurrentAllocatedCount
public long getCurrentAllocatedCount()Description copied from interface:ManagedPoolGet the approximate number of currently allocated objects.This operation has time complexity O(poolSize) to count the number of slots.
The default implementation of this interface methods returns
-1.Unlike
ManagedPool.getAllocationCount(), this returns only the number of objects currently in the pool, which typically would be the same asManagedPool.getTargetSize().- Specified by:
getCurrentAllocatedCountin interfaceManagedPool- Returns:
- The current approximate number of allocated objects.
-
getCurrentInUseCount
public long getCurrentInUseCount()Description copied from interface:ManagedPoolGet the approximate number of objects currently in use.This operation has time complexity O(poolSize) to check each slot.
The counting operation is "weakly consistent", in a similar sense to
ConcurrentLinkedQueue.iterator().The default implementation of this interface methods returns
-1.- Specified by:
getCurrentInUseCountin interfaceManagedPool- Returns:
- number of objects currently in use
-