@ThreadSafe public class ConcurrentTaskExecutor extends AbstractExecutorService implements SelectableThreadPool
Internally, this class manages a List of the workers, which are simply TaskExecutors, and a global Set of other executors. This allows all workers and executors in the server to be found easily. The worker List is an expandable collection of internal thread workers. The decision to use a copy-on-write List instead of a Set was made based on the need for index based access, as well as the majority of operations upon the collection iterations from thread searching. Unfortunately, there are still many writes, as scaling requires the tracking of new workers, and the removal of the workers that are no longer needed.
This thread pool always maintains the starting concurrent. Scaling is done once the current workers are occupied at the time of observation. Workers are deemed as occupied if concurrent are in the process of attempting insertion into the worker's internal queue. Workers are managed by native park and unparking, rather than using conditions. This provides numerous advantages, which include reduced overhead, as it is native, and is not bound to a particular scaleLock. Additionally, native thread scheduling provides for more control over basic thread stopping, rather than using the thread queue of a condition, or default guarding intrinsics.
There are two basic locking areas: first on the thread advancement counter, and in the worker itself. They are both StampedLocks, which provide increased throughput (in fact, is the primary motivator for creating this class). In place of this class can be instead, a ThreadPoolExecutor. However, many new concurrent updates in Java 8 rationalize an effort to create a new class which fully utilizes those features, and subsequently providing this class which is optimized to execute the heterogeneous tasks provided by the server. The first scaleLock protects the index which to pull workers from the worker Set, and a separate scaleLock, per-worker, protects the internal Deque. A Deque was selected as it can be inserted from both ends, sizable, and is array-based. Tests confirm that array based collections do outperform their node-based counter parts, as there is reduced instantiation overhead. The explicitly declared scaleLock allows to check occupation of the worker, which increases scalability.
No thread pool would be complete without tuning. This class provides 3 basic tuning properties, which modify expiring concurrent. Expiring concurrent are new concurrent are those created to scale the executor. They are created when the current concurrent in the pool (including previously started expiring concurrent) are all occupied. One may modify the time which the worker expires, whether the task queue must be empty, and the maximum amount of concurrent in the pool.
Modifier and Type | Method and Description |
---|---|
boolean |
awaitTermination(long l,
TimeUnit timeUnit) |
static ConcurrentTaskExecutor |
create(int startingThreadCount,
String name) |
void |
execute(Runnable runnable) |
static Collection<ConcurrentTaskExecutor> |
executors() |
boolean |
isShutdown() |
boolean |
isTerminated() |
int |
maxThreads()
The maximum amount of expiring concurrent plus non-dying concurrent which are created when executing tasks or finding a scaled thread when
existing workers are occupied
|
boolean |
mustEmptyBeforeExpire()
Obtains whether an expiring worker will check the task list size before dieing
|
SelectableThread |
selectCore()
Selects a thread in much the same way as
SelectableThreadPool.selectNext() , however, it does not include concurrent that have been
added to the scaling pool. |
SelectableThread |
selectNext()
Obtains a worker which is available in the thread pool
|
SelectableThread |
selectScaled()
Obtains an unoccupied thread, or if none exists, create a new thread
|
void |
setMaxThreads(int maxScale)
Sets the maximum scale (explained in
SelectableThreadPool.maxThreads() |
void |
setMustEmptyBeforeExpire(boolean mustEmptyBeforeExpire)
Ensures there are no tasks in an expiring worker before it dies
|
void |
setThreadExpiryTime(long expireIntervalMillis)
Sets the interval at which an expiring worker will die after inactivity
|
void |
shutdown()
Shuts down the thread processes
|
List<Runnable> |
shutdownNow() |
<T> Future<T> |
submit(Callable<T> task)
Adds support for running a runnable with callback
|
long |
threadExpiryTime()
The interval at which an expiring worker will die after inactivity
|
List<SelectableThread> |
workers()
Lists all available task executors from the concurrent
|
invokeAll, invokeAll, invokeAny, invokeAny, newTaskFor, newTaskFor, submit, submit
public int maxThreads()
SelectableThreadPool
maxThreads
in interface SelectableThreadPool
50
public void setMaxThreads(int maxScale)
SelectableThreadPool
SelectableThreadPool.maxThreads()
setMaxThreads
in interface SelectableThreadPool
maxScale
- the maximum extra scaling concurrentpublic long threadExpiryTime()
SelectableThreadPool
threadExpiryTime
in interface SelectableThreadPool
public void setThreadExpiryTime(long expireIntervalMillis)
SelectableThreadPool
setThreadExpiryTime
in interface SelectableThreadPool
expireIntervalMillis
- the interval, in millisecondspublic boolean mustEmptyBeforeExpire()
SelectableThreadPool
mustEmptyBeforeExpire
in interface SelectableThreadPool
true
(default) to indiciate the worker does check the task list sizepublic void setMustEmptyBeforeExpire(boolean mustEmptyBeforeExpire)
SelectableThreadPool
setMustEmptyBeforeExpire
in interface SelectableThreadPool
mustEmptyBeforeExpire
- true
(default) if the worker needs to ensure the task list is emptypublic static ConcurrentTaskExecutor create(int startingThreadCount, String name)
@InternalUseOnly public static Collection<ConcurrentTaskExecutor> executors()
public SelectableThread selectCore()
SelectableThreadPool
SelectableThreadPool.selectNext()
, however, it does not include concurrent that have been
added to the scaling pool.
This is useful for caching SelectableThreads for thread-confinement
selectCore
in interface SelectableThreadPool
public SelectableThread selectNext()
SelectableThreadPool
Unlike using SelectableThreadPool.selectScaled()
, this does not create a new thread if all workers are occupied.
Obtaining an executor and immediately adding a task is a broken idiom.
Store the executor, or use Executor.execute(Runnable)
selectNext
in interface SelectableThreadPool
public SelectableThread selectScaled()
SelectableThreadPool
The new thread, if created, will expire. The default time is 60 seconds, if there are no tasks left.
The timer is not renewed if there are still tasks. The timer is a lazy long
stamp set when tasks are polled
if the worker wakes up spuriously or a task is added.
Obtaining an executor and immediately adding a task is a broken idiom.
Store the executor, or use Executor.execute(Runnable)
selectScaled
in interface SelectableThreadPool
public List<SelectableThread> workers()
SelectableThreadPool
workers
in interface SelectableThreadPool
public void shutdown()
SelectableThreadPool
shutdown
in interface ExecutorService
shutdown
in interface SelectableThreadPool
public List<Runnable> shutdownNow()
shutdownNow
in interface ExecutorService
public boolean isShutdown()
isShutdown
in interface ExecutorService
public boolean isTerminated()
isTerminated
in interface ExecutorService
public boolean awaitTermination(long l, TimeUnit timeUnit) throws InterruptedException
awaitTermination
in interface ExecutorService
InterruptedException
@Nonnull public <T> Future<T> submit(Callable<T> task)
SelectableThreadPool
submit
in interface ExecutorService
submit
in interface SelectableThreadPool
submit
in class AbstractExecutorService
task
- the callback to runCopyright © 2016. All rights reserved.