当前位置:网站首页>ReentrantLock工作原理
ReentrantLock工作原理
2022-08-02 02:36:00 【季风泯灭的季节】
- 一般是通过一个内部类Sync继承 AQS
- 将同步器所有调用都映射到Sync对应的方法

- 阻塞等待队列
- 共享/独占
- 公平/非公平
- 可重入
- 允许中断
- state表示资源的可用状态
- State三种访问方式:
- getState()
- setState()
- compareAndSetState()
- Exclusive-独占,只有一个线程能执行,如ReentrantLock
- Share-共享,多个线程可以同时执行,如Semaphore/CountDownLatch
- 同步等待队列: 主要用于维护获取锁失败时入队的线程
- 条件等待队列: 调用await()的时候会释放锁,然后线程会加入到条件队列,调用signal()唤醒的时候会把条件队列中的线程节点移动到同步队列中,等待再次获得锁
ReentrantLock
- 可中断
- 可以设置超时时间
- 可以设置为公平锁
- 支持多个条件变量
- 与 synchronized 一样,都支持可重入

synchronized和ReentrantLock的区别:
- synchronized关键字,是JVM层次的锁实现,ReentrantLock是类,是JDK层次基于AQS的锁实现;二者都是可重入的独占锁。
- synchronized的锁状态是无法在代码中直接判断的,但是ReentrantLock可以通过 ReentrantLock#isLocked判断;
- synchronized自动加解锁,ReentrantLock要手动加解锁,它的操作更加灵活。
- synchronized是非公平锁,ReentrantLock是可以是公平也可以是非公平的;ReentrantLock要保证公平性也会引入额外的开销,导致吞吐量下降,慎用。
- synchronized是不可以被中断的,而ReentrantLock#lockInterruptibly方法是可以被中断的;
- 在发生异常时synchronized会自动释放锁,而ReentrantLock需要开发者在finally块中显示释放锁;
- ReentrantLock获取锁的形式有多种:如立即返回是否成功的tryLock(),以及等待指定时长的获取,更加灵活;
- synchronized在特定的情况下对于已经在等待的线程是后来的线程先获得锁(回顾一下sychronized的唤醒策略),而ReentrantLock对于已经在等待的线程是先来的线程先获得锁;
- 在低竞争情况下synchronized的性能优于ReentrantLock。在高并发下,synchronized操作monitor涉及线程的用户态、内核态的切换,性能不如ReentrantLock。
ReentrantLock的使用
同步执行,类似于synchronized
private static int sum = 0;
private static Lock lock = new ReentrantLock();
//private static TulingLock lock = new TulingLock();
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(()->{
//加锁
lock.lock();
try {
// 临界区代码
// TODO 业务逻辑:读写操作不能保证线程安全
for (int j = 0; j < 10000; j++) {
sum++;
}
} finally {
// 解锁
lock.unlock();
}
});
thread.start();
}
Thread.sleep(2000);
System.out.println(sum);
}可重入
public static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
method1();
}
public static void method1() {
lock.lock();
try {
log.debug("execute method1");
method2();
} finally {
lock.unlock();
}
}
public static void method2() {
lock.lock();
try {
log.debug("execute method2");
method3();
} finally {
lock.unlock();
}
}
public static void method3() {
lock.lock();
try {
log.debug("execute method3");
} finally {
lock.unlock();
}
}可中断
ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
log.debug("t1启动...");
try {
lock.lockInterruptibly();
try {
log.debug("t1获得了锁");
} finally {
lock.unlock();
}
} catch (InterruptedException e) {
e.printStackTrace();
log.debug("t1等锁的过程中被中断");
}
}, "t1");
lock.lock();
try {
log.debug("main线程获得了锁");
t1.start();
//先让线程t1执行
Thread.sleep(1000);
t1.interrupt();
log.debug("线程t1执行中断");
} finally {
lock.unlock();
}锁超时
ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
log.debug("t1启动...");
// 注意: 即使是设置的公平锁,此方法也会立即返回获取锁成功或失败,公平策略不生效
// if (!lock.tryLock()) {
// log.debug("t1获取锁失败,立即返回false");
// return;
// }
//超时
try {
if (!lock.tryLock(1, TimeUnit.SECONDS)) {
log.debug("等待 1s 后获取锁失败,返回");
return;
}
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
try {
log.debug("t1获得了锁");
} finally {
lock.unlock();
}
}, "t1");
lock.lock();
try {
log.debug("main线程获得了锁");
t1.start();
//先让线程t1执行
Thread.sleep(2000);
} finally {
lock.unlock();
}公平锁
//ReentrantLock lock = new ReentrantLock(true); //公平锁
ReentrantLock lock = new ReentrantLock(); //非公平锁
for (int i = 0; i < 500; i++) {
new Thread(() -> {
lock.lock();
try {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug(Thread.currentThread().getName() + " running...");
} finally {
lock.unlock();
}
}, "t" + i).start();
}
// 1s 之后去争抢锁
Thread.sleep(1000);
for (int i = 0; i < 500; i++) {
new Thread(() -> {
lock.lock();
try {
log.debug(Thread.currentThread().getName() + " running...");
} finally {
lock.unlock();
}
}, "强行插入" + i).start();
}条件变量
private static ReentrantLock lock = new ReentrantLock();
private static Condition cigCon = lock.newCondition();
private static Condition takeCon = lock.newCondition();
private static boolean hashcig = false;
private static boolean hastakeout = false;
//送烟
public void cigratee(){
lock.lock();
try {
while(!hashcig){
try {
log.debug("没有烟,歇一会");
cigCon.await();
}catch (Exception e){
e.printStackTrace();
}
}
log.debug("有烟了,干活");
}finally {
lock.unlock();
}
}
//送外卖
public void takeout(){
lock.lock();
try {
while(!hastakeout){
try {
log.debug("没有饭,歇一会");
takeCon.await();
}catch (Exception e){
e.printStackTrace();
}
}
log.debug("有饭了,干活");
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockDemo6 test = new ReentrantLockDemo6();
new Thread(() ->{
test.cigratee();
}).start();
new Thread(() -> {
test.takeout();
}).start();
new Thread(() ->{
lock.lock();
try {
hashcig = true;
log.debug("唤醒送烟的等待线程");
cigCon.signal();
}finally {
lock.unlock();
}
},"t1").start();
new Thread(() ->{
lock.lock();
try {
hastakeout = true;
log.debug("唤醒送饭的等待线程");
takeCon.signal();
}finally {
lock.unlock();
}
},"t2").start();
}ReentrantLock源码
加锁:
- CAS加锁,成功后将重入线程设置为当前线程。重入数加1。
- 如果加锁失败则将线程放入一个双向链表的等待队列,并调用unsafe.park()挂起线程。
解锁:
- 直接将重入线程设置为null,将state还原为0。
- 调用unsafe.park()唤起等待队列中的一个线程去竞争锁。
边栏推荐
猜你喜欢

Nanoprobes丨1-巯基-(三甘醇)甲醚功能化金纳米颗粒

The first time I wrote a programming interview question for Niu Ke: input a string and return the letter with the most occurrences of the string

2022-08-01 mysql/stoonedb slow SQL-Q18 analysis

Remember a gorm transaction and debug to solve mysql deadlock

四元数、罗德里格斯公式、欧拉角、旋转矩阵推导和资料

Power button 1374. Generate each character string is an odd number

使用docker安装mysql

IMU预积分的简单理解

Talking about the "horizontal, vertical and vertical" development trend of domestic ERP

机器人领域期刊会议汇总
随机推荐
2022-07-30 mysql8 executes slow SQL-Q17 analysis
openGauss切换后state状态显示不对
【ORB_SLAM2】void Frame::AssignFeaturesToGrid()
淘宝详情.
Rasa 3 x learning series - Rasa - 4873 dispatcher Issues. Utter_message study notes
IMU预积分的简单理解
考完PMP学什么?前方软考等着你~
[ORB_SLAM2] SetPose, UpdatePoseMatrices
CASE2023
[Unity entry plan] 2D Game Kit: A preliminary understanding of the composition of 2D games
Chopper webshell feature analysis
2022河南青训联赛第(三)场
很有意思的经历,很有意思的项目--文件夹对比工具
EasyGBS平台播放视频时偶尔出现播放失败是什么原因?
TKU remembers a single-point QPS optimization (I wish ITEYE is finally back)
mockjs生成假数据的基本使用
PHP live source code to achieve simple barrage effect related code
Nanoprobes丨1-mercapto-(triethylene glycol) methyl ether functionalized gold nanoparticles
优炫数据库导库导错了能恢复吗?
Pinduoduo leverages the consumer expo to promote the upgrading of domestic agricultural products brands and keep pace with international high-quality agricultural products