释义

广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。ReentrantLock和synchronized都是可重入锁,下面是一个用synchronized实现的例子:

public class ReentrantTest implements Runnable {

public synchronized void get() {

System.out.println(Thread.currentThread().getName());

set();

}

public synchronized void set() {

System.out.println(Thread.currentThread().getName());

}

public void run() {

get();

}

public static void main(String[] args) {

ReentrantTest rt = new ReentrantTest();

for(;;){

new Thread(rt).start();

}

}

}

整个过程没有发生死锁的情况,截取一部分输出结果如下:

Thread-8492

Thread-8492

Thread-8494

Thread-8494

Thread-8495

Thread-8495

Thread-8493

Thread-8493

set()和get()同时输出了线程名称,表明即使递归使用synchronized也没有发生死锁,证明其是可重入的。

不可重入锁

不可重入锁,与可重入锁相反,不可递归调用,递归调用就发生死锁。看到一个经典的讲解,使用自旋锁来模拟一个不可重入锁,代码如下:

import java.util.concurrent.atomic.AtomicReference;

public class UnreentrantLock {

private AtomicReference owner = new AtomicReference();

public void lock() {

Thread current = Thread.currentThread();

//这句是很经典的“自旋”语法,AtomicInteger中也有

for (;;) {

if (!owner.compareAndSet(null, current)) {

return;

}

}

}

public void unlock() {

Thread current = Thread.currentThread();

owner.compareAndSet(current, null);

}

}

代码也比较简单,使用原子引用来存放线程,同一线程两次调用lock()方法,如果不执行unlock()释放锁的话,第二次调用自旋的时候就会产生死锁,这个锁就不是可重入的,而实际上同一个线程不必每次都去释放锁再来获取锁,这样的调度切换是很耗资源的。稍微改一下,把它变成一个可重入锁:

import java.util.concurrent.atomic.AtomicReference;

public class UnreentrantLock {

private AtomicReference owner = new AtomicReference();

private int state = 0;

public void lock() {

Thread current = Thread.currentThread();

if (current == owner.get()) {

state++;

return;

}

//这句是很经典的“自旋”式语法,AtomicInteger中也有

for (;;) {

if (!owner.compareAndSet(null, current)) {

return;

}

}

}

public void unlock() {

Thread current = Thread.currentThread();

if (current == owner.get()) {

if (state != 0) {

state--;

} else {

owner.compareAndSet(current, null);

}

}

}

}

在执行每次操作之前,判断当前锁持有者是否是当前对象,采用state计数,不用每次去释放锁。

ReentrantLock中可重入锁实现

这里看非公平锁的锁获取方法:

final boolean nonfairTryAcquire(int acquires) {

final Thread current = Thread.currentThread();

int c = getState();

if (c == 0) {

if (compareAndSetState(0, acquires)) {

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中维护了一个private volatile int state来计数重入次数,避免了频繁的持有释放操作,这样既提升了效率,又避免了死锁。

java重入锁_java并发编程:可重入锁是什么?相关推荐

  1. java的尝试性问题_Java并发编程实战 03互斥锁 解决原子性问题

    文章系列 摘要 在上一篇文章02Java如何解决可见性和有序性问题当中,我们解决了可见性和有序性的问题,那么还有一个原子性问题咱们还没解决.在第一篇文章01并发编程的Bug源头当中,讲到了把一个或者多 ...

  2. java公平锁和非公平锁_java并发编程学习之再谈公平锁和非公平锁

    在java并发编程学习之显示锁Lock里有提过公平锁和非公平锁,我们知道他的使用方式,以及非公平锁的性能较高,在AQS源码分析的基础上,我们看看NonfairSync和FairSync的区别在什么地方 ...

  3. java公平索非公平锁_Java 并发编程中使用 ReentrantLock 替代 synchronized

    Java 5 引入的 Concurrent 并发库软件包中,提供了 ReentrantLock 可重入同步锁,用来替代 synchronized 关键字原语,并可提供更好的性能,以及更强大的功能.使用 ...

  4. java投票锁_Java并发编程锁之独占公平锁与非公平锁比较

    Java并发编程锁之独占公平锁与非公平锁比较 公平锁和非公平锁理解: 在上一篇文章中,我们知道了非公平锁.其实Java中还存在着公平锁呢.公平二字怎么理解呢?和我们现实理解是一样的.大家去排队本着先来 ...

  5. java 共享锁 独占锁_Java并发编程锁之独占公平锁与非公平锁比较

    Java并发编程锁之独占公平锁与非公平锁比较 公平锁和非公平锁理解: 在上一篇文章中,我们知道了非公平锁.其实Java中还存在着公平锁呢.公平二字怎么理解呢?和我们现实理解是一样的.大家取排队本着先来 ...

  6. java 自旋锁_Java并发编程的艺术05-队列自旋锁

    Queue Spin-Lock 队列锁是一种可扩展自旋锁的方法,这种实现比BackoffLock稍微复杂一些,但是却有更好的移植性.在BackoffLock算法中有两个问题: 1. cache一致性流 ...

  7. java中解决脏读_java并发编程学习之脏读代码示例及处理

    使用interrupt()中断线程     当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一个标志,表示它已经被中断,并立即 ...

  8. java 等待几秒_Java并发编程synchronized相关面试题总结

    说说自己对于synchronized关键字的了解 synchronized关键字用于解决多个线程之间访问资源的同步性,synchronized关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个 ...

  9. java 关闭守护线程_Java并发编程之线程生命周期、守护线程、优先级、关闭和join、sleep、yield、interrupt...

    Java并发编程中,其中一个难点是对线程生命周期的理解,和多种线程控制方法.线程沟通方法的灵活运用.这些方法和概念之间彼此联系紧密,共同构成了Java并发编程基石之一. Java线程的生命周期 Jav ...

最新文章

  1. SVN使用教程之——分支、合并
  2. python生成器使用场景桌面_Python – 如何更简洁地使用生成器?
  3. 前端必备,JavaScript面试问题及答案
  4. 【杂谈】如何让你的2020年秋招CV项目经历更加硬核,可深入学习有三秋季划4大领域32个方向(2020.7.23号后涨价)
  5. SpringJunit测试类 BaseTest(转)
  6. SAP WebIDE 是如何加载SAP UI5里自定义的XML view的 - JerryMaster.view.xml
  7. 易语言神经网络验证码识别_递归神经网络 GRU+CTC+CNN 教会验证码识别
  8. python快递代取系统_代取快递的变现方式,校园跑腿的经营范围有多大?
  9. java情人节_情人节写给女朋友Java Swing代码程序
  10. 数组中的两个常见异常
  11. 杭电1597 find the nth digit
  12. 用户自定义函数代替游标进行循环拼接
  13. This dependency was not found: * !!vue-style-loader!css-loader? 解决方案
  14. 埃森哲:AI成新生产要素,2035年将中国经济增速提高1.6% | 附下载
  15. bzoj千题计划254:bzoj2286: [Sdoi2011]消耗战
  16. Xcode6无法安装VVDocumenter插件的解决方法
  17. html返回底部代码,返回页面顶部及去页面底部的js实现代码
  18. 一个Android健身APP源码(类似KEEP、FEEL、轻+、减约、薄荷等)
  19. 大数据和人工智能概念全面解析
  20. C#Code128条形码生成

热门文章

  1. MyBatis设计模式总结
  2. 循环结构_while循环
  3. Hive的基本操作-创建内部表
  4. 改造消费方解决地址硬编码问题
  5. 对称加密算法 - Java加密与安全
  6. 结合webpack配置_前端 Webpack 工程化的最佳实践
  7. drop 很慢 物化视图_终于解决了物化视图复制的问题
  8. GitLab初次安装后,登录GitLab网页的管理员账号和密码各是什么?
  9. 210226阶段三 systemV信号量
  10. 如何将低压精密运算放大器的性能扩展到高压高侧电流检测应用(高电流电阻采集电压电路图及误差分析)