Juc07_乐观锁和悲观锁、公平锁和非公平锁、递归锁(可重入锁)、死锁及排查、自旋锁(二)

简介: ③. 可重入锁(又名递归锁)

③. 可重入锁(又名递归锁)


  • ①. 什么是可重入锁?


可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提,锁对象得是同一个对象),不会因为之前已经获取过还没有释放而阻塞


如果是1个有synchronized修饰得递归调用方法,程序第2次进入被自己阻塞了岂不是天大的笑话,出现了作茧自缚


所以Java中ReentrantLock和Synchronized都是可重入锁,可重入锁的一个优点是可在一定程度避免死锁


②. 可重入锁这四个字分开解释


可: 可以 | 重: 再次 | 入: 进入 | 锁: 同步锁 | 进入什么:进入同步域(即同步代码块、方法或显示锁锁定的代码)


③. 代码验证synchronized和ReentrantLock是可重入锁



//synchronized 是可重入锁
class Phone{
    public synchronized void sendSms() throws Exception{
        System.out.println(Thread.currentThread().getName()+"\tsendSms");
        sendEmail();
    }
    public synchronized void sendEmail() throws Exception{
        System.out.println(Thread.currentThread().getName()+"\tsendEmail");
    }
}
/**
 * Description:
 *  可重入锁(也叫做递归锁)
 *  指的是同一先生外层函数获得锁后,内层敌对函数任然能获取该锁的代码
 *  在同一线程外外层方法获取锁的时候,在进入内层方法会自动获取锁
 *  *  也就是说,线程可以进入任何一个它已经标记的锁所同步的代码块
 *  **/
public class ReenterLockDemo {
    /**
     * t1 sendSms
     * t1 sendEmail
     * t2 sendSms
     * t2 sendEmail
     * @param args
     */
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{
            try {
                phone.sendSms();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"t1").start();
        new Thread(()->{
            try {
                phone.sendSms();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"t2").start();
    }
}


//ReentrantLock 是可重入锁
  class Phone implements Runnable {
      private Lock lock = new ReentrantLock();
      @Override
      public void run() {
          get();
      }
      private void get() {
          lock.lock();
          try {
              System.out.println(Thread.currentThread().getName() + "\tget");
              set();
          } finally {
              lock.unlock();
          }
      }
      private void set() {
          lock.lock();
          try {
              System.out.println(Thread.currentThread().getName() + "\tset");
          } finally {
              lock.unlock();
          }
      }
  }
  /**
   * Description:
   * 可重入锁(也叫做递归锁)
   * 指的是同一先生外层函数获得锁后,内层敌对函数任然能获取该锁的代码
   * 在同一线程外外层方法获取锁的时候,在进入内层方法会自动获取锁
   * <p>
   * 也就是说,线程可以进入任何一个它已经标记的锁所同步的代码块
   **/
  public class ReenterLockDemo {
      /**
       * Thread-0 get
       * Thread-0 set
       * Thread-1 get
       * Thread-1 set
       */
      public static void main(String[] args) {
          Phone phone = new Phone();
          Thread t3 = new Thread(phone);
          Thread t4 = new Thread(phone);
          t3.start();
          t4.start();
      }
  }


④. 可重入锁的种类


隐式锁(即synchronized关键字使用的锁)默认是可重入锁,在同步块、同步方法使用


(在一个synchronized修饰的方法或者代码块的内部调用本类的其他synchronized修饰的方法或代码块时,是永远可以得到锁的)


显示锁(即Lock)也有ReentrantLock这样的可重入锁


(lock和unlock一定要一 一匹配,如果少了或多了,都会坑到别的线程)


⑤. Synchronized的重入的实现机理(为什么任何一个对象都可以成为一个锁)


每个锁对象拥有一个锁计数器和一个指向持有该锁的线程的指针


当执行monitorenter时,如果目标锁对象的计数器为零,那么说明它没有被其他线程所持


有,Java虚拟机会将该锁对象的持有线程设置为当前线程,并且将计数器加1


在目标锁对象的计数器不为零的情况下,如果锁对象的持有线程时当前线程,那么Java虚拟


机可以将其计数器加1,否则需要等待,直到持有线程释放该锁


当执行monitorexit,Java虚拟机则需将锁对象的计数器减1。计数器为零代表锁已经释放


微信图片_20220106185402.png




相关文章
|
2月前
|
安全 Java
大厂面试题详解:synchronized的偏向锁和自旋锁怎么实现的
字节跳动大厂面试题详解:synchronized的偏向锁和自旋锁怎么实现的
31 0
|
2月前
多线程并发锁方案—自旋锁
多线程并发锁方案—自旋锁
|
8月前
|
存储
5. 多线程并发锁
5. 多线程并发锁
24 0
理论:第十章:公平锁,非公平锁,可重入锁,递归锁,自旋锁,读写锁,悲观锁,乐观锁,行锁,表锁,死锁,分布式锁,线程同步锁分别是什么?
理论:第十章:公平锁,非公平锁,可重入锁,递归锁,自旋锁,读写锁,悲观锁,乐观锁,行锁,表锁,死锁,分布式锁,线程同步锁分别是什么?
|
程序员 调度 开发工具
面试官:你说说互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景
「互斥锁、自旋锁、读写锁、乐观锁、悲观锁」的选择和使用
面试官:你说说互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景
|
程序员 调度 UED
面试官:你说说互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景?(一)
生活中用到的锁,用途都比较简单粗暴,上锁基本是为了防止外人进来、电动车被偷等等。 但生活中也不是没有 BUG 的,比如加锁的电动车在「广西 - 窃·格瓦拉」面前,锁就是形同虚设,只要他愿意,他就可以轻轻松松地把你电动车给「顺走」,不然打工怎么会是他这辈子不可能的事情呢?牛逼之人,必有牛逼之处。
263 0
面试官:你说说互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景?(一)