可重入锁,也叫递归锁
可重入锁:指的是同一个线程外层函数获得锁之后,内层递归函数仍然能获取该锁的代码,在同一个线程在外层方法获取锁的时候,进入内层方法会自动获取锁
种类:ReentrantLock 和 synchronized 都是可重入锁
作用:避免死锁
注意点:用了锁,一定要记得开锁和关锁,lock和unlock方法都是一对一对的出现,避免出现错误,如果少了其中的一个,就会报错。
ReentrantLock 版本:
public class MyLock_1 { public static void main(String[] args) { Mylock(); new Thread(()->{ Mylock(); }).start(); } static ReentrantLock reentrantLock = new ReentrantLock(); public static void Mylock(){ reentrantLock.lock(); try { System.out.println("第一把锁:"+Thread.currentThread().getId()); Lock lock = new ReentrantLock(); lock.lock(); try { System.out.println("第二把锁:"+Thread.currentThread().getId()); }finally { lock.unlock(); } }catch (Exception ex){ ex.printStackTrace(); }finally { reentrantLock.unlock(); } } }
结果:
synchronized 版本:其实一层里面再套一层,多层,但是获取到的对象都是第一把锁,锁住的对象。
public class Xttblog { public static void main(String[] args) { Xttblog child = new Xttblog(); child.doSomething(); } public synchronized void doSomething() { System.out.println("child.doSomething()" + Thread.currentThread().getName()); doAnotherThing(); // 调用自己类中其他的synchronized方法 } private synchronized void doAnotherThing() { super.doSomething(); // 调用父类的synchronized方法 System.out.println("child.doAnotherThing()" + Thread.currentThread().getName()); } } class SuperXttblog { public synchronized void doSomething() { System.out.println("father.doSomething()" + Thread.currentThread().getName()); } }
结果:
可重入锁的原理: 详情到时看 ReentrantLock 源码
重入锁实现可重入性原理或机制是:每一个锁关联一个线程持有者和计数器,当计数器为 0 时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;
当某一线程请求成功后,JVM会记下锁的持有线程,并且将计数器置为 1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,
同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为 0,则释放该锁。
不可重入锁:
定义:所谓不可重入锁,即若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞。
我们尝试设计一个不可重入锁 (参考网上大佬)
package sss; public class myLock_2 { public static void main(String[] args) throws InterruptedException { new count().print(); } } class count{ //声明一把锁对象,全局锁 Lock lock = new Lock(); public void print() throws InterruptedException{ lock.lock(); doAdd(); lock.unlock(); } public void doAdd() throws InterruptedException { lock.lock(); //这里会因为得不到锁对象这里阻塞 System.out.println("这是doAdd()"); lock.unlock(); } } class Lock{ //定义一把锁 private boolean isLocked = false; public synchronized void lock() throws InterruptedException { while (isLocked){ wait(); } isLocked = true; } public synchronized void unlock(){ isLocked = false; notify(); } }
不可重入锁的本质: 由于线程之间的获取资源的加上了锁,却没有释放锁,导致程序的后面无法得到锁对象资源而出现了阻塞,其实也就是线程之间的通信出现了障碍。