广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。
可重入锁:
ReentrantLock和synchronized都是可重入锁,下面是一个用synchronized实现的例子:
整个过程没有发生死锁的情况,截取一部分输出结果如下:
set()和get()同时输出了线程名称,表明即使递归使用synchronized也没有发生死锁,证明其是可重入的。
不可重入锁
不可重入锁,与可重入锁相反,不可递归调用,递归调用就发生死锁。
自定义模拟不可重入锁:
一个经典的讲解,使用自旋锁来模拟一个不可重入锁,代码如下:
package com.thread;
import java.util.concurrent.atomic.AtomicReference;
public class UnreentrantLock {
private AtomicReference<Thread> owner = new AtomicReference<Thread>();//记录当前锁的持有线程对象
public void lock() {//加锁
Thread current = Thread.currentThread();//获取当前线程对象
for (; ; ) {//自旋(被当前线程或其他线程持有锁,就会循环)
if (owner.compareAndSet(null, current)) {//只有锁可用即为null,才能设置当前线程为锁持有对象,并返回true
return;
}
}
}
public void unlock() {//解锁
Thread current = Thread.currentThread();//获取当前线程对象
owner.compareAndSet(current, null);//设置锁的持有对象为null
}
}
使用原子引用来存放线程,同一线程两次调用lock()方法,如果不执行unlock()释放锁的话,第二次调用自旋的时候就会产生死锁,这个锁就不是可重入的。
自定义模拟可重入锁:
实际上同一个线程不必每次都去释放锁再来获取锁,这样的调度切换是很耗资源的。稍微改一下,把它变成一个可重入锁:
package com.thread;
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 (owner.compareAndSet(null, current)) {//当前锁可用
state = 1;//状态置为1
return;
} else {
if (current == owner.get()) {//如果当前线程持有锁
state++;//重入次数加1
return;
}
for (; ; ) {//被其他线程持有就会继续循环
if (owner.compareAndSet(null, current)) {//只有锁可用即为null,才能设置当前线程为锁持有对象,并返回true
return;
}
}
}
}
public void unlock() {//解锁
Thread current = Thread.currentThread();//获取当前线程对象
if (current == owner.get()) {//如果当前线程持有锁
if (state > 0) {//重入次数大于0
state--;//重入次数减1
} else {
owner.compareAndSet(current, null);//设置锁的持有对象为null
}
}
}
}
在执行每次操作之前,判断当前锁持有者是否是当前对象,采用state计数,不用每次去释放锁。
ReentrantLock中非公平的可重入锁实现:
// 非公平方式获取锁,用于tryLock()方法
final boolean nonfairTryAcquire(int acquires) {
//当前线程
final Thread current = Thread.currentThread();
// 继承至AbstractQueuedSynchronizer的方法
int c = getState();//获取锁状态值
//没有线程正在竞争该锁
if (c == 0) {
// 继承至AbstractQueuedSynchronizer的方法
if (compareAndSetState(0, acquires)) {//若state为0则将state修改为acquires的值,状态0表示锁没有被占用
setExclusiveOwnerThread(current);// 设置当前线程独占
return true;// 成功
}
} else if (current == getExclusiveOwnerThread()) {// 当前线程拥有该锁
int nextc = c + acquires;// 增加重入次数
if (nextc < 0) // overflow(计数值小于0,则抛出异常)
throw new Error("Maximum lock count exceeded");
// 继承至AbstractQueuedSynchronizer的方法
setState(nextc);//设置锁状态值
return true;// 成功
}
return false;// 失败
}