20230608 java.util.concurrent.locks.ReentrantLock
介绍
java.util.concurrent.locks.ReentrantLock
public class ReentrantLock implements Lock, java.io.Serializable
ReentrantLock
是使用 AQS 的标准范式
API
构造器
ReentrantLock()
ReentrantLock(boolean fair)
- fair :是否公平锁,默认非公平锁
public
实现接口 java.util.concurrent.locks.Lock
- lock
- lockInterruptibly
- tryLock
- tryLock
- unlock
- newCondition
其他 public
- getHoldCount
- 当前线程持有此锁的次数,如果此锁未被当前线程持有,则为零
- isHeldByCurrentThread
- 查询此锁是否由当前线程持有
- isLocked
- 查询此锁是否被任何线程持有
- 此方法设计用于监视系统状态,而不用于同步控制
- isFair
- 是否公平锁
- hasQueuedThreads
final boolean hasQueuedThreads()
- 查询是否有任何线程正在等待获取此锁
- 注意,因为取消可能随时发生,所以true返回并不能保证任何其他线程都会获得此锁。此方法主要用于监视系统状态。
- hasQueuedThread
final boolean hasQueuedThread(Thread thread)
- 查询入参线程是否正在等待获取此锁
- getQueueLength
int getQueueLength()
- 返回等待获取此锁的线程数的估计值
- 该值只是一个估计值,因为当此方法遍历内部数据结构时,线程数可能会动态变化。此方法设计用于监视系统状态,而不用于同步控制
- hasWaiters
boolean hasWaiters(Condition condition)
- 查询是否有任何线程正在等待与此锁关联的 Condition
- 注意,由于超时和中断可能随时发生,因此true返回并不能保证未来的signal会唤醒任何线程。此方法主要用于监视系统状态。
- getWaitQueueLength
int getWaitQueueLength(Condition condition)
- 返回等待与此锁关联的 Condition 的线程数的估计值
代码理解
ReentrantLock
实现 Lock
接口,内部锁实现使用 AQS AbstractQueuedSynchronizer
读代码时,需要关联 AbstractQueuedSynchronizer
一起读
包含三个静态内部类,分别是
abstract static class Sync extends AbstractQueuedSynchronizer
static final class NonfairSync extends Sync
static final class FairSync extends Sync
定义同步器:
private final Sync sync;
AbstractQueuedSynchronizer.state
在 ReentrantLock
中代表的是线程持有锁的次数
公平锁
公平锁的实现对比 FairSync
和 NonfairSync
,区别在于
- initialTryLock
- tryAcquire
这两个方法都在 ReentrantLock#lock
方法调用中用到,两者实现的区别是 FairSync
在设置 state 前会调用 hasQueuedPredecessors
判断是否有任何线程等待获取的时间比当前线程长
ReentrantLock#tryLock
始终是非公平的
示例代码
用于调试理解的示例代码:
package study.hwj.v1p12.lock;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
/**
* TestReentrantLock
*
* @author owenwjhuang
* @date 2023/6/8
*/
public class TestReentrantLock {
public static void main(String[] args) throws InterruptedException {
// testTryLock();
// testSingleThread();
testTwoThread();
// testThreeThread();
}
private static void testThreeThread() {
ReentrantLock reentrantLock = new ReentrantLock();
Runnable runnable = () -> {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread() + ":11:" + reentrantLock);
reentrantLock.lock();
System.out.println(Thread.currentThread() + ":12:" + reentrantLock);
};
Thread thread1 = new Thread(runnable, "111");
Thread thread2 = new Thread(runnable, "222");
System.out.println(Thread.currentThread() + ":00:" + reentrantLock);
reentrantLock.lock();
System.out.println(Thread.currentThread() + ":01:" + reentrantLock);
thread1.start();
thread2.start();
Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
allStackTraces.forEach((k, v) -> {
System.out.println("==============");
System.out.println(k);
System.out.println(Arrays.toString(v));
});
}
/**
* 单个线程
*/
private static void testTwoThread() throws InterruptedException {
ReentrantLock reentrantLock = new ReentrantLock();
new Thread(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName());
reentrantLock.lock();
reentrantLock.unlock();
}).start();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
reentrantLock.lock();
Thread.sleep(100000);
reentrantLock.unlock();
}
/**
* 单个线程
*/
private static void testSingleThread() {
ReentrantLock reentrantLock = new ReentrantLock();
System.out.println("1::" + reentrantLock);
reentrantLock.lock();
System.out.println("2::" + reentrantLock);
reentrantLock.lock();
System.out.println("3::" + reentrantLock);
reentrantLock.unlock();
System.out.println("4::" + reentrantLock);
}
private static void testTryLock() {
ReentrantLock reentrantLock = new ReentrantLock();
System.out.println("1::" + reentrantLock);
boolean b1 = reentrantLock.tryLock();
System.out.println("b1::" + b1);
System.out.println("2::" + reentrantLock);
boolean b2 = reentrantLock.tryLock();
System.out.println("b2::" + b2);
System.out.println("3::" + reentrantLock);
reentrantLock.unlock();
System.out.println("4::" + reentrantLock);
}
}