Thread pools address two different problems: they usually provide improved performance when executing large numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and managing the resources, including threads, consumed when executing a collection of tasks. Each ThreadPoolExecutor also maintains some basic statistics, such as the number of completed tasks.
To be useful across a wide range of contexts, this class provides many adjustable parameters and extensibility hooks. However, programmers are urged to use the more convenient Executors factory methods Executors.NewCachedThreadPool() (unbounded thread pool, with automatic thread reclamation), Executors.NewFixedThreadPool(int) or Executors.NewFixedThreadPool(int, IThreadFactory ) (fixed size thread pool) and Executors.NewSingleThreadExecutor() single background thread), that preconfigure settings for the most common usage scenarios. Otherwise, use the following guide when manually configuring and tuning this class:
When a new task is submitted in method AbstractExecutorService.Execute(Action) or AbstractExecutorService.Execute(IRunnable) and fewer than CorePoolSize threads are running, a new thread is created to handle the request, even if other worker threads are idle. If there are more than CorePoolSize but less than MaximumPoolSize threads running, a new thread will be created only if the queue is full. By setting core pool size and maximum pool size the same, you create a fixed-size thread pool. By setting maximum pool size to an essentially unbounded value such as int.MaxValue, you allow the pool to accommodate an arbitrary number of concurrent tasks. Most typically, core and maximum pool sizes are set only upon construction, but they may also be changed dynamically using CorePoolSize and MaximumPoolSize.
There are three general strategies for queuing:
It is possible to define and use other kinds of IRejectedExecutionHandler classes. Doing so requires some care especially when policies are designed to work only under particular capacity or queuing policies.
If hook or callback methods throw exceptions, internal worker threads may in turn fail and abruptly terminate. internal class PausableThreadPoolExecutor : ThreadPoolExecutor { private boolean _isPaused; private ReentrantLock _pauseLock = new ReentrantLock(); private ICondition _unpaused = pauseLock.NewCondition(); public PausableThreadPoolExecutor(...) : base( ... ) { } protected override void BeforeExecute(Thread t, IRunnable r) { base.BeforeExecute(t, r); _pauseLock.Lock(); try { while (_isPaused) _unpaused.Await(); } catch (ThreadInterruptedException ie) { t.Interrupt(); } finally { _pauseLock.Unlock(); } } public void Pause() { using(_pauseLock.Lock()) { _isPaused = true; } } public void Resume() { using(_pauseLock.Lock()) { _isPaused = false; _unpaused.SignalAll(); } } }