• 大厂面试题:ReentrantLock 与 synchronized异同点对比


    写在开头

    在过去的博文中我们学习了ReentrantLocksynchronized这两种Java并发使用频率最高的同步锁,在很多大厂面试题中有个经典考题:

    ReentrantLock 与 synchronized异同点对比!

    今天我们针对这一考题来做一个尽可能全面的总结哈。

    ReentrantLock 与 synchronized

    ReentrantLock是一种独占式的可重入锁,位于java.util.concurrent.locks中,是Lock接口的默认实现类,底部的同步特性基于AQS实现,和synchronized关键字类似,但更灵活、功能更强大、也是目前实战中使用频率非常高的同步类。

    synchronized 依赖于 JVM 而 ReentrantLock 依赖于 API

    synchronized 是依赖于 JVM 实现的,虚拟机团队在 JDK1.6 为 synchronized 关键字进行了很多优化,但是这些优化都是在虚拟机层面实现的,并没有直接暴露给我们。

    ReentrantLock 是 JDK 层面实现的(也就是 API 层面,需要 lock() 和 unlock() 方法配合 try/finally 语句块来完成),ReentrantLock 比 synchronized 增加了一些高级功能。

    区别罗列

    1. ReentrantLock 是一个类,而 synchronized 是 Java 中的关键字;
    2. ReentrantLock 必须手动释放锁。通常需要在 finally 块中调用 unlock 方法以确保锁被正确释放;
    3. ReentrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁;
    4. synchronized 会自动释放锁,当同步块执行完毕时,由 JVM 自动释放,不需要手动操作;
    5. ReentrantLock 可以实现多路选择通知(可以绑定多个 Condition),而 synchronized 只能通过 wait 和 notify/notifyAll 方法唤醒一个线程或者唤醒全部线程(单路通知);
    6. ReentrantLock提供了一种能够中断等待锁的线程的机制,通过 lock.lockInterruptibly() 来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。而synchronized不具备这种特点。
    7. ReentrantLock: 通常提供更好的性能,特别是在高竞争环境下;
    8. synchronized: 在某些情况下,性能可能稍差一些,但随着 JDK 版本的升级,性能差距已经不大了。

    【注】:Condition是 JDK1.5 之后才有的,它具有很好的灵活性,比如可以实现多路通知功能也就是在一个Lock对象中可以创建多个Condition实例(即对象监视器),线程对象可以注册在指定的Condition中,从而可以有选择性的进行线程通知,在调度线程上更加灵活,我们在后面的学习中会耽误聊一聊它!

    性能对比

    虽然说JDK1.6后synchronized的性能有很大的提升了,但是相比较而言,两者之间仍然存在性能差别,我们通过一个小demo来测试一下。

    public class Test {
    
        private static final int NUM_THREADS = 10;
        private static final int NUM_INCREMENTS = 1000000;
    
        private int count1 = 0;
        private int count2 = 0;
    
        private final ReentrantLock lock = new ReentrantLock();
        private final Object syncLock = new Object();
    
        public void increment1() {
            lock.lock();
            try {
                count1++;
            } finally {
                lock.unlock();
            }
        }
    
        public void increment2() {
            synchronized (syncLock) {
                count2++;
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
    
            Test test = new Test();
    
            // ReentrantLock性能测试
            long startTime = System.nanoTime();
            Thread[] threads = new Thread[NUM_THREADS];
            for (int i = 0; i < NUM_THREADS; i++) {
                threads[i] = new Thread(() -> {
                    for (int j = 0; j < NUM_INCREMENTS; j++) {
                        test.increment1();
                    }
                });
                threads[i].start();
            }
            for (Thread thread : threads) {
                thread.join();
            }
            long endTime = System.nanoTime();
            System.out.println("ReentrantLock完成时间: " + (endTime - startTime) + " ns");
    
            // synchronized性能测试
            startTime = System.nanoTime();
            for (int i = 0; i < NUM_THREADS; i++) {
                threads[i] = new Thread(() -> {
                    for (int j = 0; j < NUM_INCREMENTS; j++) {
                        test.increment2();
                    }
                });
                threads[i].start();
            }
            for (Thread thread : threads) {
                thread.join();
            }
            endTime = System.nanoTime();
            System.out.println("synchronized完成时间: " + (endTime - startTime) + " ns");
        }
    }
    

    我们采用10个线程,每个线程做加1000000操作,执行时间对比如下:

    //1000000万数据量时
    ReentrantLock完成时间: 272427700 ns
    synchronized完成时间: 675759100 ns
    
    //10000数据量时
    ReentrantLock完成时间: 52207600 ns
    synchronized完成时间: 11291600 ns
    

    很明显在数据量比较大的时候,竞争激烈时,ReentrantLock的性能要比synchronized好很多,但在数据量较低的情况下,会呈现出不同的结果。

    结尾彩蛋

    如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

    image

    如果您想与Build哥的关系更近一步,还可以关注“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!

    image

  • 相关阅读:
    YOLOv8/5不显示FLPOs
    [贪心][二分]Sort Zero Codeforces1712C
    c 语言stdlib.h介绍
    c#设计模式-行为型模式 之 访问者模式
    ATT&CK框架现有的14个战术进行了详细介绍
    antd+react Hook弹窗改进版
    c++11 多线程支持 (std::shared_future)
    [附源码]Python计算机毕业设计SSM交通事故记录信息管理系统(程序+LW)
    更优雅的OrientDB Java API
    05 uniapp/微信小程序 项目day05
  • 原文地址:https://www.cnblogs.com/JavaBuild/p/18149963