• 【面试题】公平锁和非公平锁/可重入锁


    1. 公平锁和非公平锁

    1.1 是什么

    公平锁 :按照线程在队列中的排队顺序,先到者先拿到锁
    非公平锁 :当线程要获取锁时,先通过两次 CAS 操作去抢锁,如果没抢到,当前线程再加入到队列中等待唤醒。

    1.2 两者区别

    非公平锁在调用 lock 后,首先就会调用 CAS 进行一次抢锁,如果这个时候恰巧锁没有被占用,那么直接就获取到锁返回了。
    非公平锁在 CAS 失败后,和公平锁一样都会进入到 tryAcquire 方法,在 tryAcquire 方法中,如果发现锁这个时候被释放了(state == 0),非公平锁会直接 CAS 抢锁,但是公平锁会判断等待队列是否有线程处于等待状态,如果有则不去抢锁,乖乖排到后面。

    公平锁和非公平锁就这两点区别,如果这两次 CAS 都不成功,那么后面非公平锁和公平锁是一样的,都要进入到阻塞队列等待唤醒。

    2. 可重入锁(递归锁)

    同一线程,在外层方法获取锁后,内层方法自动获取锁。也就是说,线程可以进入任何一个他已经拥有锁同步的方法。

    public synchronized void  method1(){
       method2();
    }
    public synchronized void  method2(){
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.1 可重入锁有哪些

    ReentrantLock/synchronized

    2.2 可重入锁作用

    避免死锁。

    2.3 可重入锁demo --synchronized

    class Phone {
        synchronized void  sendSMS(){
            System.out.println(Thread.currentThread().getName()+"---sendSMS");
            sendEmail();
        }
        synchronized void sendEmail(){
            System.out.println(Thread.currentThread().getName()+"---sendEmail");
        }
    }
    public class TestArrayList {
    
        public static void main(String[] args) {
            Phone phone = new Phone();
    
            new Thread(()->{
                phone.sendSMS();
            },"t1").start();
    
            new Thread(()->{
                phone.sendSMS();
            },"t2").start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    2.4 可重入锁demo --ReentrantLock

    class Phone implements Runnable {
    
        Lock lock = new ReentrantLock();
    
        @Override
        public void run() {
            method1();
        }
    
        void method1() {
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "--method1--lock");
                method2();
            } finally {
                lock.unlock();
                System.out.println(Thread.currentThread().getName() + "--method1--unlock");
            }
        }
    
        void method2() {
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "--method2--lock");
            } finally {
                lock.unlock();
                System.out.println(Thread.currentThread().getName() + "--method2--unlock");
            }
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Phone phone = new Phone();
            Thread t1 = new Thread(phone, "t1");
            Thread t2 = new Thread(phone, "t2");
            t1.start();
            t2.start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    在这里插入图片描述

  • 相关阅读:
    flink的Standalone-HA模式安装
    8. String to Integer (atoi)
    JavaScript篇
    SpringBoot
    时序预测 | Matlab灰色-马尔科夫预测
    使用Spring Initailizr功能~
    【优化选址】基于遗传算法求解分布式电源的选址定容问题附matlab代码
    SrpingMVC中的简单配置、注解及工作流程
    Linux 调试之strace
    向上转型和向下转型
  • 原文地址:https://blog.csdn.net/yzx3105/article/details/126618496