介绍
上一篇文章我们分析了简单锁的缺点,发现简单锁竟然自己可以把自己死锁.所以可重入锁出现了,可重入锁就是为了解决自己和自己死锁的问题.锁的内部可以记住哪个线程持有锁.这样保证已经获得锁的线程不会再次获得锁
实现
我们的实现可以根据简单锁改进.
版本1
public class CustomReentrantLock1 {
AtomicInteger atomicInteger = new AtomicInteger();
volatile Thread curThread;
public void lock() {
while (!atomicInteger.compareAndSet(0, 1)) {
if (curThread == Thread.currentThread()) break;
}
curThread = Thread.currentThread();
}
public void unLock() {
curThread = null;
atomicInteger.set(0);
}
static CustomReentrantLock1 lock = new CustomReentrantLock1();
public static void main(String[] args) {
lock.lock();
methodA();
lock.unLock();
}
private static void methodA() {
lock.lock();
//do something
lock.unLock();
}
复制代码
以上实现是否可行?
我们仔细观察,运行,发现好像不行.代码中的例子中,调用了两次lock.lock();
,而只调用一次 lock.unLock();
发现就把锁了两次的lock给释放了.所以上面的实现是不正确的.我们需要有一个变量来记录一个线程调用了多少次lock.lock
版本2
在版本1之上改进:
import java.util.concurrent.atomic.AtomicInteger;
public class CustomReentrantLock2 {
AtomicInteger atomicInteger = new AtomicInteger();
volatile Thread curThread;
volatile int count;
public void lock() {
while (!atomicInteger.compareAndSet(0, 1)) {
if (curThread == Thread.currentThread()) {
count += 1;
return;
}
Thread.onSpinWait();//让出cpu,但是还在竞争队列里
}
curThread = Thread.currentThread();
count = 1;
}
public void unLock() {
if (curThread != Thread.currentThread()) return;
count -= 1;
if (count == 0) {
curThread = null;
atomicInteger.set(0);
}
}
static CustomReentrantLock2 lock = new CustomReentrantLock2();
public static void main(String[] args) {
lock.lock();
methodA();
lock.unLock();
}
private static void methodA() {
lock.lock();
//do something
lock.unLock();
}
}
复制代码
加了一个被 volatile修饰的count,这时我们的可重入锁好像就实现了.
扩展
问:我们是否还有其他的方式来实现可重入锁?是否可以用ThreadLocal来记录这些东西?是否可以使用ThreadLocal实现一个可重入锁?
答:可以
下篇文章介绍公平锁
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END