锁的分类
什么是可重入锁
可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提锁对象得是同一个对象或者class),不会因为之前已经获取过还没释放而阻塞。Java中ReentrantLock和synchronized都是可重入锁,可重入锁的一个优点是可一定程度避免死锁。
ReentrantLock和synchronized都是重入锁,
可重入锁的好处:【1.避免死锁】【2.提升封装性】
案例实现
电影院预定预定电影院座位
预定座位就是个很好的lock锁场景,预定座位,其实这个背后就是上锁了
首先ReentrantLock和NonReentrantLock都继承父类AQS,其父类AQS中维护了一个同步状态status来计数重入次数,status初始值为0。当线程尝试获取锁时,可重入锁先尝试获取并更新status值,如果status == 0表示没有其他线程在执行同步代码,则把status置为1,当前线程开始执行。如果status != 0,则判断当前线程是否是获取到这个锁的线程,如果是的话执行status+1,且当前线程可以再次获取锁。而非可重入锁是直接去获取并尝试更新当前status的值,如果status != 0的话会导致其获取锁失败,当前线程阻塞。释放锁时,可重入锁同样先获取当前status的值,在当前线程是持有锁的线程的前提下。如果status-1 == 0,则表示当前线程所有重复获取锁的操作都已经执行完毕,然后该线程才会真正释放锁。而非可重入锁则是在确定当前线程是持有锁的线程之后,直接将status置为0,将锁释放。
测试lock 锁的可重入性
我们使用 lock.getHoldCount() 打印下获取锁的次数 多次获取锁,与释放锁会发现锁不用等待,下一次依然可以获取到锁,这就是锁的可重入锁性
不可重入锁
不可重入锁,与可重入锁相反,不可递归调用,递归调用就会发生死锁。