2024-03-23  阅读(50)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/mianshi/baodian/detail/1366098696

synchronizedReentrantLock 两者的功能是一致的,都是 Java 中用于管理并发和同步机制的,但它们两者之间还是存在一些差异的。

用法不同

  • synchronized 可用来修饰普通方法、静态方法和代码块
    public synchronized void  test() {
        //... 
    }
    
    public  void  test() {
        synchronized (this) {
            //...  
        }
    }
  • ReentrantLock 只能用在代码块上。
    private final ReentrantLock lock = new ReentrantLock();
    
    public void test() {
        // 加锁
        lock.lock();
        try {
            // ...
        } finally {
            // 释放锁
            lock.unlock();
        }
    }

获取锁和释放锁机制不同

  • synchronized 的获取锁和释放锁是自动的,当进入 synchronized 修饰的方法或者方法体内,会自动获取锁,当执行完成后会自动释放锁。

  • ReentrantLock 需要显示地获取锁和释放锁。

由于ReentrantLock 需要显示调用 unlock() 释放锁,所以一定千万要主要不能漏调用这个方法,同事也需要将该方法调用逻辑放在 finally 中。

公平性

  • synchronized 不保证公平性。所以,线程获取锁的顺序是不可预测的,不能保证先请求锁的线程先获取锁。
  • ReentrantLock 支持公平锁和非公平锁,如果设置为公平锁,则 ReentrantLock 能保证先请求锁的会先获取锁。

响应中断

  • synchronized 不能响应中断。
  • ReentrantLock 提供了 lockInterruptibly() 来支持响应中断的能力,可以使线程在等待锁的过程中响应中断。

用代码演示下:

public class ReentrantLockTest {
    private final Lock lock = new ReentrantLock();

    public void lockInterruptiblyTest() {
        try {
            lock.lockInterruptibly();

            try {
                System.out.println(Thread.currentThread().getName() + "-成功获取锁;;;" + LocalTime.now());

                Thread.sleep(5000);
            } finally {
                lock.unlock();
                System.out.println(Thread.currentThread().getName() + "-成功释放锁;;;" + LocalTime.now());
            }
        } catch (InterruptedException e) {
            // 响应中断
            System.out.println(Thread.currentThread().getName() + "-响应中断;;;" + LocalTime.now());
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ReentrantLockTest lockTest = new ReentrantLockTest();
        Thread thread01 = new Thread(lockTest::lockInterruptiblyTest);
        Thread thread02 = new Thread(lockTest::lockInterruptiblyTest);

        // thread01 先启动,获取锁
        thread01.start();
        // sleep(1000) 等待线程 1 先获取锁
        Thread.sleep(1000);

        // thread02 后启动
        thread02.start();
        // sleep(1000) 后 ,thread02 中断
        Thread.sleep(1000);
        thread02.interrupt();
    }
}

执行结果:

底层实现

  • synchronized 是 JVM 层面通过监视器(Monitor)实现的。
  • ReentrantLock 则是 Java 层次的,是通过 AQS 的 API 实现的。

功能丰富性

ReentrantLock 提供了比 synchronized 更多的功能,比如支持获取锁响应中断、获取锁超时,还提供了一个写 API 如getHoldCount()isHeldByCurrentThread()getQueueLength() 等,这些可以帮助我们详细管理锁的状态。


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文