文章目录
关系图:
一、简介
ReentrantLock
可重入锁
即
lock.lock()
可多次, 但释放相等次数lock.unlock()
但倘若多释放lock.lock()
, 则会抛异常
ReentrantLock
对于 Lock
接口的实现主要依赖了 Sync
使用步骤:
- 定义
state
为0时, 可以获取资源并置为 1 - 若已获得资源,
state
不断加 1 - 在释放资源时,
state
减 1, 直至为 0
二、使用
比如同时累加
public class ReentrantLockTest extends Thread {
private static ReentrantLock lock = new ReentrantLock();
private String name;
private static int i = 0;
private ReentrantLockTest(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name + " 开始增加");
for (int j = 0; j < 100; j++) {
lock.lock();
try {
++i;
} finally {
lock.unlock();
}
}
System.out.println(name + " 结束增加");
}
public static void main(String[] args) throws InterruptedException {
ReentrantLockTest test1 = new ReentrantLockTest("thread1");
ReentrantLockTest test2 = new ReentrantLockTest("thread2");
test1.start();
test2.start();
test1.join();
test2.join();
System.out.println(i);
}
}
三、源码分析
方法图:
(0) ReentrantLock()
默认创建不公平锁, 即当上一个线程释放锁的时候, 随机下一个线程获得锁
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
(1) lock()
// ReentrantLock.java
public void lock() {
sync.lock();
}
// ReentrantLock.java NonfairSync.java
final void lock() {
if (compareAndSetState(0, 1)) // CAS, 尝试设置 state = 1
setExclusiveOwnerThread(Thread.currentThread()); // 设置拥有这个锁的线程
else
acquire(1); // 尝试获取
}
// AQS
public final void acquire(int arg) {
// 获取失败, 且加入了队列
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt(); // 自我中断, 阻塞
}
// ReentrantLock.java tryAcquire
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) { // 尝试设置 state = 1
setExclusiveOwnerThread(current); // 获取锁成功, 则设置自己拥有锁的线程为当前线程
return true;
}
}
else if (current == getExclusiveOwnerThread()) { // 如果拥有锁的线程为当前线程
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc); // 记录重入次数
return true;
}
return false;
}
// AQS
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor(); // 获取前一个节点
if (p == head && tryAcquire(arg)) { // 如果为头节点 且 尝试获取锁成功
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// 获取失败后挂起, 挂起后并检查中断情况
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
(2) lockInterruptibly()
// ReentrantLock.java
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
// AQS
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted()) // 是否可中断
throw new InterruptedException();
if (!tryAcquire(arg)) // 尝试获取
doAcquireInterruptibly(arg);
}
// AQS
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
(3) tryLock()
// ReentrantLock.java
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
// AQS
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
(4) unlock()
// ReentrantLock.java
public void unlock() {
sync.release(1);
}
// ReentrantLock.java
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
四、应用场景
多线程并发同步
五、参考资料
- <<码出高效>>