查看原文
其他

别再被面试官吓到了,让我带你了解 synchronized 和 ReentrantLock 的区别

编程导航-聪 面试鸭 2024-03-29

引言:在 Java 多线程编程领域,理解 synchronized 关键字与 ReentrantLock 类的区别及各自的应用场景是每个 Java 开发者成长路径上的一项关键挑战。如果你对这两种同步机制的区别还不够清晰,那么在面试或实际开发过程中遇到相关问题时可能会觉得手足无措。但不用担心,本文旨在深化你对这两种关键并发工具的理解,帮助你在讨论多线程同步控制时能够展现出自信,清晰地解释它们之间的不同点及各自最适用的场景。

题目

别再被面试官吓到了,让我带你了解 synchronized 和 ReentrantLock 的区别

推荐解析

了解 synchronized 和 ReentrantLock

synchronized

1)是 Java 内置的关键字,用于提供对象或方法级别的同步机制。

2)它能够确保在同一时刻只有一个线程可以执行 synchronized 修饰的方法或代码块。

3)不需要手动释放锁,当 synchronized 方法或代码块执行完毕后,锁自动释放。

4)锁的获取和释放是隐式的,为开发者提供了便捷的线程同步机制。

5)不支持公平锁、可中断锁等高级功能。

ReentrantLock

1)属于 java.util.concurrent.locks 包下的一个类,提供了比 synchronized 更广泛的锁操作。

2)必须手动声明锁的获取和释放(通过 lock()unlock() 方法)。

3)支持许多高级功能,如可中断的锁等待、公平锁、锁续租等。

4)支持可中断的锁等待( lockInterruptibly()

5)提供了条件变量(Condition)支持,允许分开管理线程间的通信。

简单示例

synchronized 示例

public class SynchronizedExample {
    public synchronized void syncMethod() {
        // 同步方法体
    }

    public void syncBlock() {
        synchronized (this) {
            // 同步代码块
        }
    }
}

ReentrantLock 示例

1)非公平锁

javaCopy codeimport java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockExample {
    private final ReentrantLock lock = new ReentrantLock(); // 默认非公平锁

    public void lockMethod() {
        lock.lock();
        try {
            // 受保护的代码区
        } finally {
            lock.unlock();
        }
    }
}

2)公平锁

javaCopy codeimport java.util.concurrent.locks.ReentrantLock;

public class FairReentrantLockExample {
    private final ReentrantLock lock = new ReentrantLock(true); // 启用公平锁

    public void fairLockMethod() {
        lock.lock();
        try {
            // 公平锁保证按请求锁的顺序获取锁
        } finally {
            lock.unlock();
        }
    }
}

加深记忆的例子

1)synchronized:可以比喻为家里的卫生间一次只能一个人使用。当有人在使用时,其他人必须等待,直到里面的人用完出来。这个过程完全自动化,使用者不需要手动锁门或解锁。

2)ReentrantLock:则像是有一个可控的门禁系统。你可以决定谁能进入,是否允许排队,以及何时结束使用。它提供了更多控制,比如允许尝试获取资源而不是无限等待,或者按照到达顺序来获取资源。

其他补充

鱼聪明 AI 的回答:

鱼聪明 AI 地址:https://www.yucongming.com/

使用场景

1)synchronized:适用于简单的同步需求,如小规模的并发控制,或者不需要可中断锁、公平锁等高级功能的场景。

2)ReentrantLock:适用于复杂的并发控制场景,特别是需要利用条件变量、公平锁、可中断锁等高级功能时。

公平锁和非公平锁

公平锁

公平锁是指多个线程按照请求锁的顺序来获取锁,遵循先来先得的原则。如果锁已被其他线程占用,新来的线程就会进入等待队列。只有当队列中的前面所有线程都获取到锁并释放后,该线程才能获得锁。这种机制虽然保证了锁分配的绝对公平性,但是会导致更大的线程切换开销和整体吞吐量的降低,因为频繁的线程调度会消耗大量的系统资源。

优点:

1)确保无饥饿发生,每个线程最终都可以获取到锁。

2)适用于事务处理等对执行顺序敏感的场景。

缺点:

1)效率较低,因为要保证按照请求顺序获得锁,可能导致线程切换和等待的增加。

2)可能会造成锁的平均获取时间延长。

非公平锁

非公平锁是指多个线程获取锁的顺序并不是按照请求锁的顺序,允许"插队"。新请求的锁可能会直接获得锁,即使有其他线程正在等待。这种方式不保证等待的线程能够按照请求顺序获得锁,但是在多数情况下能够减少唤醒和阻塞的次数,从而提高系统的吞吐量。

优点:

1)效率更高,因为减少了队列的调度,可以更快地获得锁,提高了程序的响应速度和吞吐量。

2)在非竞争或低竞争的环境下,性能优于公平锁。

缺点:

1)可能会导致线程饥饿,即某些线程可能会很长时间获取不到锁。

2)在高度竞争的环境下,线程可能会不断地尝试获取锁,从而增加CPU的负担。

推荐文章和书籍

文章:https://zhuanlan.zhihu.com/p/86293659

书籍:《 Java 核心技术卷 I 》

欢迎交流

在阅读完本文后,你应该对 Java 多线程中的 synchronized 关键字和 ReentrantLock 类有了深入的理解。了解这两种同步机制的特性和区别,将使你能够在设计并发控制策略、提高应用性能以及优化资源管理方面,与面试官或同事进行深入的讨论。为了进一步加深理解,并促进知识的共享与进步,本文提出以下三个问题,欢迎大家在评论区交流观点:

1)在什么情况下应该优先考虑使用 synchronized 关键字而非 ReentrantLock,反之亦然?它们在不同的应用场景下各自有什么优势?

2)如何根据具体的并发需求选择使用 synchronized 或 ReentrantLock ,以构建高效且灵活的同步策略?在处理高并发数据时,这两种机制如何帮助优化性能和资源利用?

3)在并发处理和多线程环境下,synchronized 与 ReentrantLock 的性能表现如何?它们对应用的性能和稳定性有何影响?

通过探讨这些问题,我们不仅能够深化对 synchronized 和 ReentrantLock 的理解,而且还能够学习如何根据实际需求选择最适合的同步机制。期待你的参与和贡献,让我们一起在 Java 并发编程的路上更进一步。

点燃求职热情!每周持续更新,海量面试题等你挑战!赶紧关注面试鸭公众号,轻松备战春招和暑期实习!


继续滑动看下一个
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存