We know that almost all modern machine processors are multi-core and multi-thread. The multi-core and multi-thread mechanism is introduced to improve the overall processing performance of the machine as much as possible. However, multi-core and multi-threading also bring a lot of concurrency problems, one of the most important problems is data contention, data contention is that multiple threads access the shared data at the same time, resulting in data conflict (incorrect). Data contention, if mishandled, can mean that the entire business logic can go wrong, so this is especially important in high-concurrency environments.
Conditions under which data competition arises
Data contention scenarios must meet the following conditions:
- Multiple threads access a shared data.
- These threads access simultaneously.
- Access is the operation of reading or writing data.
- At least one thread performs write operations.
Data competition example
To better understand the data race problem, let’s use an example of data race. In the two graphs below, the top is the correct result when there is no data contention. I start out with 0 in memory, and as soon as the thread reads it it increments I by 5. After that, thread two reads the I in memory and increments it by 6, ending with I =11. In the following case, thread 2 reads I in memory before thread 1 has finished modifying it, resulting in the final result of I =6.
Synchronization with the lock
Since concurrent execution of multiple threads often involves data contention, how can we solve this problem? The answer is to introduce synchronization mechanisms that control access to shared data and solve the data race problem. The synchronization mechanism can be realized through locks, so the AQS framework also abstracts the lock acquisition and release operations. Moreover, it also provides two modes including exclusive lock and shared lock, so that the implementation of various synchronizers on the upper level is very convenient
An exclusive lock
An exclusive lock means that the lock can only be held by one thread at a time and cannot be acquired by any other thread unless the thread that already holds the lock releases it. A thread can proceed only after it has successfully acquired the lock, and when it leaves the contention area, the lock is released for other threads entering the data contention area to acquire.
Acquire and release exclusive locks correspond to acquire and release methods respectively. The main logic for acquiring an exclusive lock is to try to acquire the lock first and proceed if it succeeds, otherwise the thread is put on a wait queue and possibly suspended. The main logic for releasing an exclusive lock is to wake up one or more threads in the wait queue to attempt to acquire the lock. The following pseudocode can be used to represent the acquisition and release of an exclusive lock in AQS
Gets the pseudocode for the exclusive lock
Add Node to queue with CAS while(true){if(try to get lock &&node as head Node){set current Node to head out of loop}else{ Change the waitStatus of the Node precursor in CAS mode to Singal if(changed successfully){suspend the current thread}}}}Copy the code
Release the pseudocode for the exclusive lock
If (attempt to release the lock succeeded){wake up subsequent nodes containing threads}Copy the code
A Shared lock
Obtaining and releasing shared locks correspond to the acquireShared and releaseShared methods respectively. The main logic for acquiring a shared lock is to try to acquire the lock first and proceed if it succeeds, otherwise the thread is put on a wait queue and may be suspended. The main logic for releasing a shared lock is to wake up one or more threads in the wait queue to attempt to acquire the lock. The following pseudocode can be used to represent the acquisition and release of shared locks in AQS.
Public number: Code farm architecture
Java concurrent programming
- Concurrent Programming in Java: How Java serialization works
- Java concurrent programming: Deadlock formation conditions and handling in concurrency
- Java concurrent programming: processes, threads, parallelism, and concurrency
- Java concurrent programming: The Task Executor interface
- Concurrent programming in Java: Mutex and shared locks for AQS
- Concurrent Programming in Java: What is the JDK’s built-in concurrency framework AQS
- Concurrent Programming in Java: How to Ensure atomicity of AQS
- Concurrent Programming in Java: How to prevent deadlocks when threads block and wake up
- Concurrent Programming in Java: How do threads block and wake up