可重入锁
也叫递归锁:递归传递同一把锁
理解:
同一个线程在进入外层同步方法获得锁之后,同样可以进入该外层同步方法中所拥有的内层同步方法,它们此时所拥有的是同一把锁
这种设计可以避免死锁(如果不是可重入锁,在进入外层同步方法之后,无法进入该外层同步方法所拥有的内层同步方法,这种情况下就会出现死锁)
synchronized/ReentrantLock都是可重入锁
代码示例和解释:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 可重入锁:synchronized/ReentrantLock都是可重入锁
* 可重入锁(也叫递归锁:递归传递同一把锁)
* 同一个线程在进入外层同步方法获得锁之后,同样可以进入该外层同步方法中所拥有的内层同步方法,它们此时所拥有的是同一把锁
* 这种设计可以避免死锁(如果不是可重入锁,在进入外层同步方法之后,无法进入该外层同步方法所拥有的内层同步方法,这种情况下就会出现死锁)
*/
public class LockTest {
public static void main(String[] args){
//创建一个资源类对象实例
LockResource lockResource = new LockResource();
Runnable runnable = new Runnable() {
@Override
public void run() {
//运行外层同步方法
lockResource.sendPhoneMsg();
}
};
new Thread(runnable,"t1").start();
new Thread(runnable,"t2").start();
//让main线程暂停1秒,保证前两个线程已经运行完,再验证ReentrantLock
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println();
System.out.println();
new Thread(lockResource,"t3").start();
new Thread(lockResource,"t4").start();
}
}
//资源类
class LockResource implements Runnable{
//1)验证synchronized为可重入锁
//外层同步方法
public synchronized void sendPhoneMsg(){
System.out.println(Thread.currentThread().getName()+"---send Phone Msg...");
//内层同步方法
sendEmailMsg();
}
public synchronized void sendEmailMsg(){
System.out.println(Thread.currentThread().getName()+"---send Email Msg...");
}
//2)验证ReetrantLock为可重入锁
//创建一个ReentrantLock锁实例
Lock lock = new ReentrantLock();
//实现Runnable接口
@Override
public void run() {
//运行进入外层同步方法
sendPhone();
}
//外层同步方法
public void sendPhone(){
//加锁
lock.lock();
try{
System.out.println(Thread.currentThread().getName()+"---ReentrantLock Test send Phone Msg...");
//内层同步方法
sendEmail();
}finally{
//释放锁资源
lock.unlock();
}
}
public void sendEmail(){
//加锁
lock.lock();
try{
System.out.println(Thread.currentThread().getName()+"---ReentrantLock Test send Email Msg...");
}finally{
//释放锁资源
lock.unlock();
}
}
}
运行结果:
证明了:同一个线程在进入外层同步方法获得锁之后,同样可以进入该外层同步方法中所拥有的内层同步方法,这就是可重用锁
思考两个问题:
关于ReentrantLock的.lock()与.unlock()
问题:这里多个.lock()和.unlock()会编译报错,还是运行报错?
运行结果证明,只要是.lock()和.unlock()成对出现的,不管多少个,都可以编译通过,并运行通过
这种情况不是成对出现的,编译器并没有编译报错,可以运行,但是会造成死锁