- Java Concurrency and Multithreading Tutorial
- Multithreading Benefits
- Multithreading Costs
- Concurrency Models
- Concurrency vs. Parallelism
- Single-threaded Concurrency
- Creating and Starting Java Threads
- Race Conditions and Critical Sections
- Thread Safety and Shared Resources
- Thread Safety and Immutability
- Java Memory Model
- Java Happens Before Guarantee
- Java Synchronized Blocks
- Java Volatile Keyword
- CPU Cache Coherence in Java Concurrency
- False Sharing in Java
- Java ThreadLocal
- Thread Signaling
- Deadlock Prevention
- Starvation and Fairness
- Nested Monitor Lockout
- Slipped Conditions
- Locks in Java
- Read / Write Locks in Java
- Reentrance Lockout
- Blocking Queues
- The Producer Consumer Pattern
- Thread Pools
- Thread Congestion in Java
- Compare and Swap
- Anatomy of a Synchronizer
- Non-blocking Algorithms
- Amdahl's Law
- Java Concurrency References
Thread Congestion in Java
Thread congestion can occur when two or more threads are trying to access the same, guarded data structure at the same time. By "guarded" I mean that the data structure is guarded using synchronized blocks or a concurrent data structure (Lock, BlockingQueue etc.) so that the data structure is thread safe. The resulting thread congestion means that the threads trying to access the shared data structure are spending a high amount of time waiting in line to access the data structure - wasting valuable execution time on waiting.
Thread Blocking Data Structures May Cause Thread Congestion
A data structure which blocks threads from accessing it - depending on what other threads are currently accessing it - may cause thread congestion. If more than one thread accesses such a data structure at the same time, one or more of the threads may be queued up waiting to access the data structure.
This queuing up is not visible in your code. The queuing up happens inside the Java VM. Therefore thread congestion is not so easy to spot simply by looking at your code. You may need profiling tools to detect thread congestion - or, you need to learn where to predict thread congestion can occur.
A Blocked Thread Loses Execution Time
While a thread is blocked trying to execute a blocking data structure, it cannot do anything. Thus, while being blocked the thread loses possible execution time. The longer the thread is blocked, the more potential execution time it loses.
The More Threads - The Higher Congestion
The more threads that attempt to access a shared, blocking data structure, the higher the risk is of thread congestion occurring, and the higher the congestion may be (the number of threads queued up waiting to access the data structure).
Alleviating Thread Congestion
To alleviate thread congestion you must reduce the number of threads trying to access the blocking data structure at exactly the same time. There are several ways to do that.
Multiple Data Structures
One way to alleviate thread congestion - at least around blocking queues - is to give each consuming thread its own queue, and have the producing thread distribute the objects (e.g. tasks) among these blocking queues. This way, only 2 threads are ever accessing each queue: The producing thread and the consuming thread.
Non-blocking Concurrency Algorithms
Another way is to use non-blocking concurrency algorithms where the threads accessing the data structure are never blocked. Non-blocking concurrency algorithms and data structures can often waste less of the thread's potential execution time than blocking concurrency algorithm or data structure.