可重入锁
可重入锁又叫递归锁,指的是同一线程外层函数获得锁之后,内存递归函数仍然能获取该锁的代码,同一个线程在外层获取锁的时候,进入内层方法会自动获取锁。也就是说,线程可以进入任何一个它已经拥有的锁所同步者的代码块。
ReentrantLock/synchronized就是一个典型的可重入锁
代码验证
synchronized
public class ReenterLockDemo {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
phone.sendSMS();
}, "t1").start();
new Thread(() -> {
phone.sendSMS();
}, "t2").start();
}
}
class Phone {
public synchronized void sendSMS(){
System.out.println(Thread.currentThread().getName()+"\t invoked sendSMS()");
sendEmail();
}
public synchronized void sendEmail(){
System.out.println(Thread.currentThread().getName()+"\t invoked sendEmail()");
}
}
当t1线程执行sendSMS()方法后,该方法中调用来同步方法sendEmail()。线程t1拿到外层函数sendSMS的锁后,能继续执行内层函数sendEmail。这就是可重入锁。
ReentrantLock
public class ReenterLockDemo {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
phone.sendSMS();
}, "t1").start();
new Thread(() -> {
phone.sendSMS();
}, "t2").start();
}
}
class Phone {
Lock lock = new ReentrantLock();
public void sendSMS() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "\t invoked sendSMS()");
sendEmail();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void sendEmail() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "\t invoked sendEmail()");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
<mark>ReentrantLock 和 synchronized 不一样,需要手动释放锁,所以使用 ReentrantLock的时候一定要手动释放锁,并且加锁次数和释放次数要一样。</mark>
当sendEmail()方法中加锁了两次,而只解锁了一次。就会导致t1线程执行完sendEmail后死锁,t2线程只能不停等待t1结束!








网友评论