重入锁简介
重入锁也叫作递归锁,指的是同一个线程外层函数获取到一把锁后,内层函数同样具有这把锁的控制权限
synchronized和ReentrantLock就是重入锁对应的实现
synchronized——重量级的锁
ReentrantLock——轻量级的锁 lock()代表加入锁 unlock()代表释放锁
不可重入锁:说明当没有释放该锁时。其他线程获取该锁会进行等待
public class MyLock { //标识锁是否可用 如果值为true代表当前有线程正在使用该锁,如果为false代表没有人用锁 private boolean isLocked=false; //获取锁:加锁 public synchronized void lock() throws InterruptedException { //判断当前该锁是否正在使用 while (isLocked){ wait(); } //当前没有人使用情况下就占用该锁 isLocked=true; } //释放锁 public synchronized void unLock(){ //将当前锁资源释放 isLocked=false; //唤起正在等待使用锁的线程 notify(); } }
public class MyLockTest { MyLock myLock=new MyLock(); //A业务方法 public void print() throws InterruptedException { //获取一把锁 myLock.lock(); System.out.println("print业务方法"); doAdd(); //释放锁 myLock.unLock(); } //B业务方法 public void doAdd() throws InterruptedException { //获取一把锁 myLock.lock(); System.out.println("doAdd业务方法"); //释放锁 myLock.unLock(); } public static void main(String[] args) throws InterruptedException { MyLockTest test=new MyLockTest(); test.print(); } }
synchronized可重入性:如果当前A持有一把锁,在A业务内部调用B,那么B也同样拥有这把锁的使用权限
public class MyLockTest { //A业务方法 public synchronized void print() throws InterruptedException { //获取了一把锁 System.out.println("print业务方法"); doAdd(); } //B业务方法 public synchronized void doAdd() throws InterruptedException { System.out.println("doAdd业务方法"); //释放锁 } public static void main(String[] args) throws InterruptedException { MyLockTest test=new MyLockTest(); test.print(); } }
ReentrantLock同样具有可重入性
public class MyLockTest { //创建锁对象 Lock lock=new ReentrantLock(); //A业务方法 public void print() throws InterruptedException { //获取了一把锁 lock.lock(); System.out.println("print业务方法"); doAdd(); //释放锁 lock.unlock(); } //B业务方法 public void doAdd() throws InterruptedException { //获取了一把锁 lock.lock(); System.out.println("doAdd业务方法"); //释放锁 lock.unlock(); } public static void main(String[] args) throws InterruptedException { MyLockTest test=new MyLockTest(); test.print(); } }
ReentrantLock底层:
public ReentrantLock() { //默认非公平锁 sync = new NonfairSync(); } public ReentrantLock(boolean fair) { //如果为true代表公平锁,否则为非公平锁 sync = fair ? new FairSync() : new NonfairSync(); } public class MyReentrantLock { //标识锁是否可用 如果值为true代表当前有线程正在使用该锁,如果为false代表没有人用锁 private boolean isLocked=false; //当前线程 Thread lockedBy=null; //加锁数量计数 Integer lockedCount=0; //加锁 public synchronized void lock() throws InterruptedException { //获取当前线程 Thread thread=Thread.currentThread(); //判断当前是否正在使用锁,如果正在使用则对比当前使用要使用锁的线程和之前使用锁的线程是否一致 //如果一致代表可以重入,继续使用锁,不会发生阻塞 //如果不一致代表当前不是一个线程,则等待 while (isLocked && thread!=lockedBy){ wait(); } //占用锁 isLocked=true; //计数+1 lockedCount++; //赋值线程 lockedBy=thread; } //释放锁 public synchronized void unlock(){ //判断当前是否是用一个线程 if(Thread.currentThread()==this.lockedBy){ //锁使用计数器-1 lockedCount--; //判断计数器是否为0,如果为0则释放锁,然后唤醒正在等待的线程 if(lockedCount==0){ isLocked=false; notify(); } } } }