当前位置: 首页 > news >正文

ReentrantLock和synchronized的区别

文章目录

  • 基本使用方式的区别
  • 锁的获取和释放机制
    • synchronized的自动管理
    • ReentrantLock的手动管理
  • 等待可中断的区别
  • 尝试获取锁的能力
  • 公平锁和非公平锁
  • 条件变量的支持

基本使用方式的区别

synchronized是Java内置的关键字,使用起来比较简单:

public class SynchronizedExample {private final Object lock = new Object();public void method1() {synchronized (lock) {// 同步代码块}}public synchronized void method2() {// 同步方法}
}

而ReentrantLock是一个类,需要手动获取和释放锁:

public class ReentrantLockExample {private final ReentrantLock lock = new ReentrantLock();public void method() {lock.lock();try {// 同步代码块} finally {lock.unlock();}}
}

从使用方式上看,synchronized更简洁,而ReentrantLock需要显式地获取和释放锁,但这也给了我们更多的控制权。

锁的获取和释放机制

synchronized的自动管理

synchronized的一个重要优势是锁的获取和释放是自动的。当线程进入synchronized代码块时自动获取锁,当离开时(无论是正常结束还是抛出异常)都会自动释放锁。这样就不会出现忘记释放锁的问题。

ReentrantLock的手动管理

ReentrantLock需要手动调用unlock()方法来释放锁:

public void flexibleLockUsage() {lock.lock();try {// 可以在这里调用其他方法someMethod();// 也可以在某些条件下提前返回if (someCondition) {return; // finally块会确保锁被释放}// 更多业务逻辑} finally {lock.unlock(); // 确保锁一定会被释放}
}

等待可中断的区别

这是两者之间一个很重要的区别。synchronized不支持中断,如果一个线程在等待synchronized锁时被阻塞了,就只能一直等下去,无法响应中断。

// synchronized无法中断等待
public synchronized void uninterruptibleMethod() {// 如果线程在等待进入这个方法时被阻塞// 调用Thread.interrupt()无法中断等待
}

而ReentrantLock提供了可中断的锁获取方式:

public void interruptibleMethod() {try {lock.lockInterruptibly(); // 可以被中断的锁获取try {// 业务逻辑} finally {lock.unlock();}} catch (InterruptedException e) {// 处理中断异常Thread.currentThread().interrupt();}
}

尝试获取锁的能力

synchronized要么获取到锁,要么一直等待,没有其他选择。但ReentrantLock提供了tryLock方法,可以尝试获取锁而不阻塞:

public boolean tryDoSomething() {if (lock.tryLock()) {try {// 获取到锁,执行业务逻辑return true;} finally {lock.unlock();}} else {// 没有获取到锁,可以做其他处理return false;}
}public boolean tryDoSomethingWithTimeout() {try {if (lock.tryLock(5, TimeUnit.SECONDS)) {try {// 在5秒内获取到锁return true;} finally {lock.unlock();}} else {// 5秒内没有获取到锁return false;}} catch (InterruptedException e) {Thread.currentThread().interrupt();return false;}
}

这种能力让我们可以实现更灵活的同步策略,比如避免死锁。

公平锁和非公平锁

synchronized只支持非公平锁,也就是说不能保证等待时间最长的线程优先获得锁。而ReentrantLock可以选择是公平锁还是非公平锁:

// 非公平锁(默认)
ReentrantLock unfairLock = new ReentrantLock();// 公平锁
ReentrantLock fairLock = new ReentrantLock(true);

公平锁保证了等待时间最长的线程优先获得锁,但性能会比非公平锁差一些,因为需要维护一个有序的等待队列。

条件变量的支持

这可能是ReentrantLock相对于synchronized最大的优势之一。synchronized只能配合wait()和notify()方法使用,而且只能有一个等待条件。

// synchronized + wait/notify
public synchronized void oldWay() throws InterruptedException {while (!condition) {wait(); // 只能等待一个条件}// 执行业务逻辑
}public synchronized void notifyOthers() {condition = true;notifyAll(); // 唤醒所有等待的线程,无法精确控制
}

而ReentrantLock可以创建多个Condition,实现更精确的线程通信:

public class MultiConditionExample {private final ReentrantLock lock = new ReentrantLock();private final Condition notFull = lock.newCondition();private final Condition notEmpty = lock.newCondition();private final Object[] items = new Object[10];private int putIndex, takeIndex, count;public void put(Object item) throws InterruptedException {lock.lock();try {while (count == items.length) {notFull.await(); // 等待不满的条件}items[putIndex] = item;putIndex = (putIndex + 1) % items.length;count++;notEmpty.signal(); // 通知不空的条件} finally {lock.unlock();}}public Object take() throws InterruptedException {lock.lock();try {while (count == 0) {notEmpty.await(); // 等待不空的条件}Object item = items[takeIndex];items[takeIndex] = null;takeIndex = (takeIndex + 1) % items.length;count--;notFull.signal(); // 通知不满的条件return item;} finally {lock.unlock();}}
}

这种方式可以让生产者只唤醒消费者,消费者只唤醒生产者,避免了不必要的线程唤醒,提高了效率。

http://www.dtcms.com/a/287899.html

相关文章:

  • 第二阶段-第二章—8天Python从入门到精通【itheima】-133节(SQL——DQL——基础查询)
  • 解决Maven版本不兼容问题的终极方案
  • 操作系统1.1.1+1.1.2:操作系统的概念、功能
  • 软考高级之工程工期成本计算题
  • 神经网络:从模式组合到多层神经网络的进化
  • 自由学习记录(70)
  • Java程序猿搬砖笔记(十九)
  • 零基础 “入坑” Java--- 十二、抽象类和接口
  • 从五次方程到计算机:数学抽象如何塑造现代计算
  • 大数据之路:阿里巴巴大数据实践——日志采集与数据同步
  • 网络爬虫概念初解
  • Rust Web 全栈开发(九):增加教师管理功能
  • 对话访谈 | 盘古信息×锐明科技:中国企业高质量出海“走进去”和“走上去”
  • 实验室危险品智能管控:行为识别算法降低爆炸风险
  • 配置华为交换机接口链路聚合-支持服务器多网卡Bind
  • element ui 表格懒加载操作问题
  • 最终分配算法【论文材料】
  • OpenCV 官翻6 - Computational Photography
  • 市场数据+幸存者偏差提问,有趣的思考?
  • 基于dcmtk的dicom工具 第六章 StoreSCU 图像发送
  • 研究的艺术
  • simulink系列之模型接口表生成及自动连线脚
  • 图 —— 拓扑排序➕Bitset!
  • XSS原型与原型链
  • Linux 常用命令详解(含目录结构 / 文件操作 / 查找 / 解压缩)- 新手入门教程
  • 接口测试工具
  • PDF发票批量打印工具哪个好?高效打印发票的实用工具推荐
  • LangGraph是一个基于图计算的大语言模型应用开发框架
  • 重学Framework Input模块:如何实现按键一键启动Activity-学员作业
  • 死锁的认识与处理