AQS source code reading
Today, from the lock method of ReentrantLock, we will go deep into AQS a little bit to see how AQS achieves the purpose of locking and unlocking. First, test what happens when only one thread locks, and then test how to deal with multiple threads. , and finally look at how the unlock operation wakes up other threads.
only one thread
test code
public class TestReentantLock {
static ReentrantLock lock = new ReentrantLock(true);
static Runnable r1 = ()-> {
// 断点位置
lock.lock();
};
public static void main(String[] args) {
new Thread(r1).start();
}
}
复制代码
Implementation process
Summarize
Through this process you can get:
- When there is only one thread, the state value is set through CAS, indicating that the current lock is held by a thread
- When there is only one thread, the operations of nodes and queues are not involved
when two threads
test code
package process;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class TestReentantLock {
static ReentrantLock lock = new ReentrantLock(true);
static Runnable r1 = ()-> {
lock.lock();
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
};
static Runnable r2 = ()->{
// 断点位置
lock.lock();
};
public static void main(String[] args) throws InterruptedException {
new Thread(r1).start();
TimeUnit.SECONDS.sleep(1);
new Thread(r2).start();
}
}
复制代码
Implementation process
Summarize
- When there are two threads, use LockSupport.park() to suspend the thread to achieve the purpose of not acquiring the lock
- By setting the waitStatus value of the previous node to Node.Signal to -1, it means to wake up the subsequent node, that is, itself.
unlock() operation
test code
package process;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class TestReentantLock {
static ReentrantLock lock = new ReentrantLock(true);
static Runnable r1 = ()-> {
lock.lock();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 断点处
lock.unlock();
};
static Runnable r2 = ()->{
lock.lock();
};
public static void main(String[] args) throws InterruptedException {
new Thread(r1).start();
TimeUnit.MILLISECONDS.sleep(500);
new Thread(r2).start();
}
}
复制代码
Implementation process
Summarize
- Get the head node, and use the waitStatus of the head node to determine the unlocking of subsequent threads
Summarize
The way AQS achieves thread synchronization can be summarized as:
- Block the thread through LockSupport.park() to achieve the purpose of not being able to acquire the lock
- Atomically update the head and tail of the queue through CAS
- Through a volatile state, the purpose of identifying the state of the lock is achieved