究竟什么是可重入锁?
来源:互联网 发布:python sum axis 1 编辑:程序博客网 时间:2024/06/05 16:50
经历
很久之前就听说了可重入锁,可重入锁究竟是什么意思,以前是囫囵吞枣的,只要记住ReentrantLock和sychronized是可重入锁就行了,爱咋用咋用,好吧,原谅我的无知,最近对基础查漏补缺,发现竟然对其一问三不知,赶紧预习一波,觉得有必要写一篇博客来讲解,就当做什么都没有发生吧,嘿嘿。。。
释义
广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者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-8492Thread-8492Thread-8494Thread-8494Thread-8495Thread-8495Thread-8493Thread-8493
set()和get()同时输出了线程名称,表明即使递归使用synchronized也没有发生死锁,证明其是可重入的。
不可重入锁
不可重入锁,与可重入锁相反,不可递归调用,递归调用就发生死锁。看到一个经典的讲解,使用自旋锁来模拟一个不可重入锁,代码如下:
import java.util.concurrent.atomic.AtomicReference;public class UnreentrantLock { private AtomicReference<Thread> owner = new AtomicReference<Thread>(); 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<Thread> owner = new AtomicReference<Thread>(); 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来计数重入次数,避免了频繁的持有释放操作,这样既提升了效率,又避免了死锁。
- 究竟什么是可重入锁?
- 【问题】究竟什么是MVC
- 究竟什么是web2.0?
- 究竟什么是素数呢?
- 究竟什么是POJO?
- 究竟什么是POJO?
- 究竟什么是云安全
- 究竟什么是POJO?
- 究竟什么是产品经理
- 究竟什么是POJO?
- 究竟什么是POJO
- 转:究竟什么是POJO?
- 究竟什么是http连接
- 究竟什么是POJO?
- 究竟什么是POJO?
- 究竟什么是商业模式?
- 究竟什么是POJO?
- 究竟什么是POJO
- 佳博80系列打印机驱动开发DLL支持C#的过程
- 线程和信号
- 电磁震荡实验
- 51nod 1085 背包问题
- mysql--1.概念及安装
- 究竟什么是可重入锁?
- GukiZ and Contest
- 数位dp不要62
- 机器学习元知识
- Linux系统虚拟机的安装原理
- 普通工厂模式and抽象工厂模式
- Java的安全组成
- Ⅴ vue2.0 项目实战
- 实验二——双向链表