java重入锁_java并发编程:可重入锁是什么?
释义
广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者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并发编程:可重入锁是什么?相关推荐
- java的尝试性问题_Java并发编程实战 03互斥锁 解决原子性问题
文章系列 摘要 在上一篇文章02Java如何解决可见性和有序性问题当中,我们解决了可见性和有序性的问题,那么还有一个原子性问题咱们还没解决.在第一篇文章01并发编程的Bug源头当中,讲到了把一个或者多 ...
- java公平锁和非公平锁_java并发编程学习之再谈公平锁和非公平锁
在java并发编程学习之显示锁Lock里有提过公平锁和非公平锁,我们知道他的使用方式,以及非公平锁的性能较高,在AQS源码分析的基础上,我们看看NonfairSync和FairSync的区别在什么地方 ...
- java公平索非公平锁_Java 并发编程中使用 ReentrantLock 替代 synchronized
Java 5 引入的 Concurrent 并发库软件包中,提供了 ReentrantLock 可重入同步锁,用来替代 synchronized 关键字原语,并可提供更好的性能,以及更强大的功能.使用 ...
- java投票锁_Java并发编程锁之独占公平锁与非公平锁比较
Java并发编程锁之独占公平锁与非公平锁比较 公平锁和非公平锁理解: 在上一篇文章中,我们知道了非公平锁.其实Java中还存在着公平锁呢.公平二字怎么理解呢?和我们现实理解是一样的.大家去排队本着先来 ...
- java 共享锁 独占锁_Java并发编程锁之独占公平锁与非公平锁比较
Java并发编程锁之独占公平锁与非公平锁比较 公平锁和非公平锁理解: 在上一篇文章中,我们知道了非公平锁.其实Java中还存在着公平锁呢.公平二字怎么理解呢?和我们现实理解是一样的.大家取排队本着先来 ...
- java 自旋锁_Java并发编程的艺术05-队列自旋锁
Queue Spin-Lock 队列锁是一种可扩展自旋锁的方法,这种实现比BackoffLock稍微复杂一些,但是却有更好的移植性.在BackoffLock算法中有两个问题: 1. cache一致性流 ...
- java中解决脏读_java并发编程学习之脏读代码示例及处理
使用interrupt()中断线程 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一个标志,表示它已经被中断,并立即 ...
- java 等待几秒_Java并发编程synchronized相关面试题总结
说说自己对于synchronized关键字的了解 synchronized关键字用于解决多个线程之间访问资源的同步性,synchronized关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个 ...
- java 关闭守护线程_Java并发编程之线程生命周期、守护线程、优先级、关闭和join、sleep、yield、interrupt...
Java并发编程中,其中一个难点是对线程生命周期的理解,和多种线程控制方法.线程沟通方法的灵活运用.这些方法和概念之间彼此联系紧密,共同构成了Java并发编程基石之一. Java线程的生命周期 Jav ...
最新文章
- SVN使用教程之——分支、合并
- python生成器使用场景桌面_Python – 如何更简洁地使用生成器?
- 前端必备,JavaScript面试问题及答案
- 【杂谈】如何让你的2020年秋招CV项目经历更加硬核,可深入学习有三秋季划4大领域32个方向(2020.7.23号后涨价)
- SpringJunit测试类 BaseTest(转)
- SAP WebIDE 是如何加载SAP UI5里自定义的XML view的 - JerryMaster.view.xml
- 易语言神经网络验证码识别_递归神经网络 GRU+CTC+CNN 教会验证码识别
- python快递代取系统_代取快递的变现方式,校园跑腿的经营范围有多大?
- java情人节_情人节写给女朋友Java Swing代码程序
- 数组中的两个常见异常
- 杭电1597 find the nth digit
- 用户自定义函数代替游标进行循环拼接
- This dependency was not found: * !!vue-style-loader!css-loader? 解决方案
- 埃森哲:AI成新生产要素,2035年将中国经济增速提高1.6% | 附下载
- bzoj千题计划254:bzoj2286: [Sdoi2011]消耗战
- Xcode6无法安装VVDocumenter插件的解决方法
- html返回底部代码,返回页面顶部及去页面底部的js实现代码
- 一个Android健身APP源码(类似KEEP、FEEL、轻+、减约、薄荷等)
- 大数据和人工智能概念全面解析
- C#Code128条形码生成