Each .NET CLR based process is given a pool of threads. The size of the thread pool is configurable however by default the maximum number of threads created by the thread pool is set to 1000 IO threads in total, and 25 worker threads per logical or physical processor. In other words, when using a dual core processor, you will have the maximum value set to 50 worker threads.
These threads are managed in a very efficient and intelligent manner by the runtime. For instance, the actual size of the thread pool varies based on how the application is consuming those threads. It is possible to set the minimum number of threads for the thread pool. Once that many threads are created, they are kept alive for the lifetime of the process. However if more threads are required, the thread pool creates new threads. Once those threads finish executing their activities, they are then returned to the thread pool. It is important to emphasise that those threads are not destroyed. They will self destroy after approximately 2 minutes of inactivity. Therefore, the usage of system resources is constantly being adjusted automatically by the thread pool itself.
Once the minimum number of threads is reached, the thread pool aims to limit the number of threads being created to one per 500 milliseconds. This is an intelligent mechanism, avoiding the expensive cost of creating a new thread when multiple thread pool threads may be released within that time period.
The combination of the above approaches makes .NET’s thread pool a very intelligent thread pool which uses as little resources as possible to give maximum performance. Therefore in most scenarios it is recommended to use this thread pool for performing asynchronous operations.
.NET’s thread pool has some shortcomings which can affect the choice between using a dedicated thread instead of a thread from the thread pool. It is usually said that a dedicated thread is favourable in the following scenarios:
- When a foreground thread is required: All thread pool threads are initialised as background threads.
- When it is required to have a thread with a particular priority.
- When a thread is required to be aborted prematurely
- When a thread must be placed in a single-threaded apartment (STA): All thread pool threads are set in the MTA apartment by default
- For long running tasks when the thread pool thread is often blocked for long periods (This may starve other parts of the application which rely on threads from the thread pool)The thread pool is shared by all AppDomains in a process. Consider this if you have more than one AppDomain in your process.