可重入锁:
如果某个线程试图获取一个已经由它自己持有的锁时,这个请求会立刻成功,并且会将这个锁的计数值加1,而当线程退出同步代码块时,计数器将会递减,当计数值为0时,释放锁。
如果没有可重入锁的支持,在第二次企图获得锁时会进入死锁状态。
通俗来说:当线程请求一个由其它线程持有的对象锁时,该线程会阻塞,而当线程请求由自己持有的对象锁时,如果该锁是重入锁,请求就会成功,否则阻塞。
可重入锁举例:
class ReentrantLockTest {
public synchronized void a() {
b();
}
public synchronized void b() {
}
public synchronized void all() {
this.a();
}
}
下面代码为例,若锁不可重入,则会在第二次获得锁时死锁。
public class LockTest {
public void test() {
//第一次获得锁
synchronized (this) {
while(true) {
//第二次获得锁
synchronized (this) {
System.out.println("ReentrantLock");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args){
new LockTest().test();
}
}
具体实现举例:
不可重入锁实现:
由于a()一直没有释放锁,所以会陷入死锁。
public class LockTest02 {
Lock lock = new Lock();
public void a() throws InterruptedException {
lock.lock();
b();
lock.unlock();
}
public void b() throws InterruptedException {
lock.lock();
//.......
lock.unlock();
}
public static void main(String[] args) throws InterruptedException {
LockTest02 test02 = new LockTest02();
test02.a();
}
}
class Lock{
//是否占用
private boolean isLocked = false;
//使用锁
public synchronized void lock() throws InterruptedException {
while(isLocked) {
wait();
}
isLocked = true;
}
//释放锁
public synchronized void unlock() {
isLocked = false;
notify();
}
}
改写成可重入锁:
加入计数器,并进行了是否是当前线程的判断
public class LockTest03 {
ReLock lock = new ReLock();
public void a() throws InterruptedException {
lock.lock();
b();
lock.unlock();
}
public void b() throws InterruptedException {
lock.lock();
//.......
lock.unlock();
}
public static void main(String[] args) throws InterruptedException {
LockTest03 test03 = new LockTest03();
test03.a();
}
}
class ReLock{
//是否占用
private boolean isLocked = false;
private Thread lockedBy = null; //存储线程
private int holdCount = 0;
//使用锁
public synchronized void lock() throws InterruptedException {
Thread t = Thread.currentThread();
while(isLocked && lockedBy != t) {
wait();
}
isLocked = true;
lockedBy = t;
holdCount++;
}
//释放锁
public synchronized void unlock() {
if(Thread.currentThread() == lockedBy){
holdCount--;
if(holdCount == 0) {
isLocked = false;
notify();
lockedBy = null;
}
}
}
}