news 2026/6/10 20:43:36

Synchronized锁升级流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Synchronized锁升级流程

文章目录

    • 引言
    • synchronized的基本使用
      • 同步方法
      • 同步代码块
    • synchronized的底层原理
      • 字节码层面分析
      • 对象头与Mark Word
    • 锁升级优化过程
      • 1. 偏向锁(Biased Locking)
      • 2. 轻量级锁(Lightweight Locking)
      • 3. 重量级锁(Heavyweight Locking)
    • 实战中的最佳实践
      • 1. 锁粒度控制
      • 2. 避免死锁
      • 3. 双检锁单例模式
    • 性能优化建议
      • 1. 减少锁持有时间
      • 2. 使用读写锁替代
    • 常见问题与解决方案
      • 1. synchronized与Lock的区别
      • 2. 如何选择锁策略
    • 总结

引言

线程安全是我们必须面对的核心挑战之一。Java为我们提供了synchronized关键字。

synchronized的基本使用

同步方法

同步方法是最简单的使用方式,直接在方法声明中添加synchronized关键字即可:

publicclassCounter{privateintcount=0;// 同步实例方法publicsynchronizedvoidincrement(){count++;}// 同步静态方法publicstaticsynchronizedvoidstaticIncrement(){// 静态方法的锁是类的Class对象}}

代码说明:

  • 实例方法的锁是当前对象实例(this)
  • 静态方法的锁是当前类的Class对象
  • 同步方法保证了同一时间只有一个线程能执行该方法

同步代码块

同步代码块提供了更细粒度的控制,可以指定锁对象:

publicclassOrderService{privatefinalObjectlock=newObject();privateMap<String,Integer>inventory=newHashMap<>();publicvoidprocessOrder(StringproductId){// 非同步代码,可以并发执行System.out.println("开始处理订单...");synchronized(lock){// 同步代码块,保证库存操作的原子性Integerstock=inventory.get(productId);if(stock!=null&&stock>0){inventory.put(productId,stock-1);System.out.println("扣减库存成功");}}// 后续非同步操作System.out.println("订单处理完成");}}

代码说明:

  • 可以指定任意对象作为锁
  • 锁的范围更小,性能更好
  • 提供了更灵活的同步控制

synchronized的底层原理

字节码层面分析

让我们通过反编译来看看synchronized在字节码层面是如何实现的:

publicclassSynchronizedDemo{privatestaticintcounter=0;privatefinalObjectlock=newObject();publicvoidsyncMethod(){synchronized(this){counter++;}}}

使用javap -c SynchronizedDemo.class反编译后,可以看到关键字节码:

public void syncMethod(); Code: 0: aload_0 1: dup 2: astore_1 3: monitorenter // 进入同步块 4: getstatic #2 // 获取counter 7: iconst_1 8: iadd 9: putstatic #2 // 设置counter 12: aload_1 13: monitorexit // 正常退出同步块 14: goto 22 17: astore_2 18: aload_1 19: monitorexit // 异常退出同步块 20: aload_2 21: athrow 22: return

关键点解析:

  • monitorenter:获取对象的监视器锁
  • monitorexit:释放对象的监视器锁
  • 编译器会自动生成异常处理,确保锁一定会被释放

对象头与Mark Word

在HotSpot虚拟机中,每个对象都有一个对象头,其中包含Mark Word,它记录了对象的锁状态信息:

锁状态存储内容标志位
无锁对象哈希码、分代年龄01
偏向锁线程ID、Epoch、分代年龄01
轻量级锁指向栈中锁记录的指针00
重量级锁指向互斥量(monitor)的指针10
GC标记11

锁升级优化过程

JDK 1.6之后,synchronized引入了锁升级机制来优化性能:

1. 偏向锁(Biased Locking)

publicclassBiasedLockExample{privatestaticfinalObjectlock=newObject();privatestaticintcount=0;publicstaticvoidmain(String[]args)throwsInterruptedException{// 默认情况下,JVM会延迟开启偏向锁Thread.sleep(5000);// 等待偏向锁开启synchronized(lock){count++;System.out.println("第一次获取锁,应该是偏向锁");}}}

偏向锁特点:

  • 适用于只有一个线程访问同步块的场景
  • 在对象头中记录线程ID
  • 同一个线程再次获取锁时不需要CAS操作

2. 轻量级锁(Lightweight Locking)

当有第二个线程尝试获取锁时,偏向锁会升级为轻量级锁:

publicclassLightweightLockExample{privatestaticfinalObjectlock=newObject();publicstaticvoidmain(String[]args){// 线程1newThread(()->{synchronized(lock){try{Thread.sleep(100);// 短暂持有锁}catch(InterruptedExceptione){e.printStackTrace();}}}).start();// 线程2 - 会触发锁升级newThread(()->{try{Thread.sleep(10);// 确保线程1先获取锁}catch(InterruptedExceptione){e.printStackTrace();}synchronized(lock){System.out.println("线程2获取锁,此时应该是轻量级锁");}}).start();}}

轻量级锁特点:

  • 使用CAS操作替代操作系统互斥量
  • 适用于线程交替执行的场景
  • 自旋等待避免线程切换开销

3. 重量级锁(Heavyweight Locking)

当竞争激烈时,轻量级锁会升级为重量级锁:

publicclassHeavyweightLockExample{privatestaticfinalObjectlock=newObject();privatestaticfinalintTHREAD_COUNT=10;publicstaticvoidmain(String[]args){CountDownLatchlatch=newCountDownLatch(THREAD_COUNT);for(inti=0;i<THREAD_COUNT;i++){newThread(()->{synchronized(lock){try{// 模拟业务处理Thread.sleep(50);}catch(InterruptedExceptione){e.printStackTrace();}}latch.countDown();}).start();}try{latch.await();System.out.println("所有线程执行完成,经历了锁升级过程");}catch(InterruptedExceptione){e.printStackTrace();}}}

重量级锁特点:

  • 使用操作系统的互斥量(Mutex)
  • 线程会进入阻塞状态
  • 适用于高竞争场景

实战中的最佳实践

1. 锁粒度控制

在商城项目中,库存管理需要特别注意锁的粒度:

publicclassInventoryManager{// 不好的做法:锁粒度太粗privatefinalObjectglobalLock=newObject();privateMap<String,Integer>inventory=newConcurrentHashMap<>();// 好的做法:细粒度锁privatefinalMap<String,Object>productLocks=newConcurrentHashMap<>();publicvoidupdateStock(StringproductId,intquantity){// 获取商品特定的锁ObjectproductLock=productLocks.computeIfAbsent(productId,k->newObject());synchronized(productLock){IntegercurrentStock=inventory.getOrDefault(productId,0);inventory.put(productId,currentStock+quantity);}}publicbooleanpurchase(StringproductId,intquantity){ObjectproductLock=productLocks.computeIfAbsent(productId,k->newObject());synchronized(productLock){IntegercurrentStock=inventory.get(productId);if(currentStock==null||currentStock<quantity){returnfalse;}inventory.put(productId,currentStock-quantity);returntrue;}}}

2. 避免死锁

在营销系统的奖品发放中,要特别注意避免死锁:

publicclassPrizeDistribution{privatefinalObjectprizeLock=newObject();privatefinalObjectuserLock=newObject();// 错误的做法:可能产生死锁publicvoiddistributePrizeWrong(longuserId,StringprizeId){synchronized(prizeLock){synchronized(userLock){// 处理奖品发放}}}// 正确的做法:固定锁顺序publicvoiddistributePrizeRight(longuserId,StringprizeId){// 按照固定顺序获取锁ObjectfirstLock,secondLock;if(System.identityHashCode(prizeLock)<System.identityHashCode(userLock)){firstLock=prizeLock;secondLock=userLock;}else{firstLock=userLock;secondLock=prizeLock;}synchronized(firstLock){synchronized(secondLock){// 安全的奖品发放逻辑System.out.println("为用户"+userId+"发放奖品"+prizeId);}}}}

3. 双检锁单例模式

在项目配置管理中,单例模式经常使用:

publicclassConfigManager{// volatile保证可见性和禁止指令重排序privatestaticvolatileConfigManagerinstance;privateConfigManager(){// 私有构造函数}publicstaticConfigManagergetInstance(){if(instance==null){// 第一次检查synchronized(ConfigManager.class){if(instance==null){// 第二次检查instance=newConfigManager();}}}returninstance;}}

为什么需要volatile:

  • 防止指令重排序
  • 保证多线程环境下的可见性
  • 避免其他线程看到未完全初始化的对象

性能优化建议

1. 减少锁持有时间

publicclassOptimizedOrderProcessor{privateMap<String,BigDecimal>prices=newHashMap<>();privateMap<String,Integer>stock=newHashMap<>();// 优化前:锁持有时间过长publicBigDecimalcalculateTotalBad(List<String>products){synchronized(this){BigDecimaltotal=BigDecimal.ZERO;for(Stringproduct:products){// 模拟耗时操作try{Thread.sleep(10);}catch(InterruptedExceptione){e.printStackTrace();}total=total.add(prices.getOrDefault(product,BigDecimal.ZERO));}returntotal;}}// 优化后:只锁必要的部分publicBigDecimalcalculateTotalGood(List<String>products){// 先收集需要的数据(不需要同步)List<BigDecimal>priceList=newArrayList<>();for(Stringproduct:products){// 模拟耗时操作try{Thread.sleep(10);}catch(InterruptedExceptione){e.printStackTrace();}}// 同步计算总和synchronized(this){BigDecimaltotal=BigDecimal.ZERO;for(Stringproduct:products){total=total.add(prices.getOrDefault(product,BigDecimal.ZERO));}returntotal;}}}

2. 使用读写锁替代

对于读多写少的场景,考虑使用ReentrantReadWriteLock

publicclassProductCache{privatefinalMap<String,Product>cache=newHashMap<>();privatefinalReentrantReadWriteLockrwLock=newReentrantReadWriteLock();publicProductgetProduct(Stringid){rwLock.readLock().lock();// 获取读锁try{returncache.get(id);}finally{rwLock.readLock().unlock();}}publicvoidupdateProduct(Productproduct){rwLock.writeLock().lock();// 获取写锁try{cache.put(product.getId(),product);}finally{rwLock.writeLock().unlock();}}}

常见问题与解决方案

1. synchronized与Lock的区别

特性synchronizedReentrantLock
实现机制JVM层面实现JDK层面实现
锁获取自动获取释放手动获取释放
可中断不支持支持
公平锁非公平可选公平/非公平
条件变量有限支持灵活支持

2. 如何选择锁策略

根据实际场景选择合适的同步机制:

publicclassLockStrategySelector{/** * 根据场景选择锁策略 * @param scenario 场景描述 * @return 建议的锁策略 */publicStringselectLockStrategy(Stringscenario){switch(scenario){case"简单同步":return"使用synchronized,简单可靠";case"需要超时":return"使用ReentrantLock.tryLock()";case"读写分离":return"使用ReentrantReadWriteLock";case"高并发统计":return"考虑使用LongAdder";case"分布式环境":return"使用分布式锁如Redis锁";default:return"使用synchronized";}}}

总结

synchronizedJava内置的同步机制,从最初的重量级锁发展到现在的智能锁升级,性能已经得到了极大的优化。在实际项目中,需要根据具体场景选择合适的同步策略:对于简单的同步需求,synchronized是选择;对于复杂的并发控制,可以考虑ReentrantLock等更灵活的机制。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 16:12:17

Qwen3双模态推理:思考与非思考模式解析

Qwen3双模态推理&#xff1a;思考与非思考模式解析 在当前AI模型越来越“大”、越来越“重”的背景下&#xff0c;一个现实问题摆在开发者面前&#xff1a;我们是否真的需要让每一个回答都经过复杂的链式推理&#xff1f;当用户问“今天星期几&#xff1f;”时&#xff0c;模型…

作者头像 李华
网站建设 2026/6/10 14:59:07

Diskinfo检测SSD缓存对TensorRT加载速度的影响

Diskinfo检测SSD缓存对TensorRT加载速度的影响 在部署AI推理系统时&#xff0c;我们常常将注意力集中在GPU算力、模型结构优化和批处理大小的调优上。然而&#xff0c;在一次边缘设备的性能测试中&#xff0c;一个看似无关紧要的现象引起了我们的注意&#xff1a;同一台设备重启…

作者头像 李华
网站建设 2026/6/9 23:56:38

EmotiVoice开源项目结构与配置详解

EmotiVoice开源项目结构与配置详解 你有没有试过让AI语音“笑”出来&#xff1f;或者让它用“愤怒”的语气读一句“今天真是糟糕透顶”&#xff1f;这不再是科幻电影的桥段——EmotiVoice 正在把这种有情绪、有温度的语音合成变成现实。 作为一个支持多情感表达和零样本声音克隆…

作者头像 李华
网站建设 2026/6/10 16:14:19

140亿参数T2V模型本地部署与性能调优

Wan2.2-T2V-A14B 本地部署与性能调优实战&#xff1a;从模型加载到工业级服务当输入“镜头缓缓推进&#xff0c;穿汉服的女孩在樱花树下旋转起舞&#xff0c;微风吹起长发&#xff0c;花瓣随风飘落”&#xff0c;系统在不到一分钟内输出一段720P、8秒长、帧间连贯且光影细腻的视…

作者头像 李华
网站建设 2026/6/10 15:45:01

企业级AI基础设施建设:TensorFlow生产部署+清华源加速方案

企业级AI基础设施建设&#xff1a;TensorFlow生产部署与清华源加速实践 在当今智能系统快速落地的背景下&#xff0c;企业对AI基础设施的要求早已超越“能跑模型”的初级阶段。稳定性、可维护性、部署效率和团队协作流畅度&#xff0c;成为衡量一套AI技术栈是否真正“可用”的关…

作者头像 李华
网站建设 2026/6/10 17:55:50

水性环保地面材料如何破解水上乐园维护难题

行业痛点分析 水上乐园地面涂装材料面临多重技术挑战。长期浸水环境导致涂层起泡脱落。高频率人流踩踏加速地面磨损。化学消毒剂持续腐蚀表面涂层。温差变化引起材料伸缩开裂。这些因素共同导致地面寿命缩短。维护成本显著增加。游客安全难以保障。行业急需性能更稳定的解决方案…

作者头像 李华