别再被面试官吓到了,让我带你了解 synchronized 和 ReentrantLock 的区别
引言:在 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 并发编程的路上更进一步。
点燃求职热情!每周持续更新,海量面试题等你挑战!赶紧关注面试鸭公众号,轻松备战春招和暑期实习!