news 2026/4/23 14:07:38

Java多线程:synchronized方法独占锁的秘密

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java多线程:synchronized方法独占锁的秘密

文章目录

  • Java多线程:synchronized方法独占锁的秘密?
    • 什么是synchronized?
    • synchronized背后的独占锁机制
      • 1. 独占锁的定义
      • 2. 锁的粒度
      • 3. 锁的获取与释放
    • 独占锁的优缺点
      • 优点
      • 缺点
    • 案例分析:synchronized方法的常见问题
      • 例子代码:
      • 问题分析
      • 解决方案
        • 方法一:细化锁粒度
        • 方法二:使用更高效的锁机制
    • 总结
    • 通过合理使用`synchronized`方法和其他并发工具(如`ReentrantLock`),我们可以写出既安全又高效的多线程代码。
      • 📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!

Java多线程:synchronized方法独占锁的秘密?

大家好,欢迎来到闫工的博客!今天我们要聊的是一个非常经典的话题——Java多线程中的synchronized关键字以及它背后的“独占锁”机制。作为一个Java开发者,你可能每天都在用synchronized,但你真的了解它的秘密吗?别急,咱们一步步来拆解这个知识点。


什么是synchronized?

首先,synchronized是Java中用来实现线程同步的一个关键字。简单来说,它用于确保在多线程环境下,同一时间只有一个线程可以执行某个方法或代码块。这样就能避免多个线程同时修改共享资源时出现的竞态条件(Race Condition)和不一致的问题。

举个栗子,假设你有一个银行账户,余额是100元。如果有两个线程同时尝试从这个账户中取钱,可能会发生以下情况:

  • 线程A读取到余额是100元,并决定取出50元。
  • 同时,线程B也读取到余额是100元,并取出30元。

这样就会导致最终的余额变成20元(100 - 50 - 30),但实际上这是错误的,因为两个线程都操作了同一个资源。为了避免这种情况,synchronized可以帮助我们实现“独占锁”,确保同一时间只有一个线程可以操作这个资源。


synchronized背后的独占锁机制

那么问题来了,synchronized是如何实现这种“独占锁”的呢?让我们从底层原理来理解这个问题。

1. 独占锁的定义

在Java中,“独占锁”指的是在同一时间只有一个线程可以持有该锁并执行被保护的方法或代码块。当一个线程进入synchronized方法时,它会获取到这把“锁”,其他尝试进入这个方法的线程必须等待,直到当前线程释放锁。

2. 锁的粒度

在Java中,synchronized可以修饰两种类型的代码:实例方法静态方法。它们分别对应不同的锁粒度:

  • 实例方法:锁是针对实例对象的。也就是说,每个实例对象都有自己的锁。
  • 静态方法:锁是针对类的。无论有多少个实例对象,所有线程在调用同一个类的静态synchronized方法时都会共享同一把锁。

举个例子:

publicclassAccount{privatedoublebalance;// 实例synchronized方法publicsynchronizedvoidwithdraw(doubleamount){if(balance>=amount){balance-=amount;}}// 静态synchronized方法publicstaticsynchronizedvoidtransfer(Accountfrom,Accountto,doubleamount){from.withdraw(amount);to.deposit(amount);}}

在这个例子中:

  • withdraw方法是实例方法,每个Account对象都有自己的锁。
  • transfer方法是静态方法,所有线程在调用这个方法时都会争夺同一个类级别的锁。

3. 锁的获取与释放

当一个线程进入synchronized方法时,它会尝试获取对应的锁。如果锁没有被其他线程持有,那么当前线程就会成功获取锁并执行方法;否则,该线程会被阻塞,直到锁被释放。

释放锁的过程发生在以下几种情况:

  • 当前线程正常退出synchronized方法。
  • 当前线程在synchronized方法中抛出异常。
  • 当前线程调用了wait()方法并释放了锁(后面会详细讲解)。

独占锁的优缺点

了解了独占锁的基本原理后,我们再来分析它的优缺点。

优点

  1. 简单易用synchronized关键字内置在Java语言中,使用起来非常方便。
  2. 自动管理:Java虚拟机(JVM)会自动管理锁的获取与释放,开发者不需要手动实现复杂的锁机制。
  3. 可重入性:一个线程可以多次进入同一个synchronized方法而不会被阻塞。

缺点

  1. 粒度较粗synchronized通常会对整个方法进行加锁,这可能会导致不必要的性能开销。如果只是其中一小部分代码需要同步,使用synchronized可能会显得过于“保守”。
  2. 死锁风险:多个线程在争夺多把锁时,可能会发生死锁(Deadlock)。例如,线程A持有锁1并试图获取锁2,而线程B持有锁2并试图获取锁1,就会导致双方都无法继续执行。

案例分析:synchronized方法的常见问题

为了更好地理解synchronized的实际应用和潜在问题,我们来看一个经典的案例——银行转账。

例子代码:

publicclassBank{publicsynchronizedvoidtransfer(Accountfrom,Accountto,doubleamount){if(from.getBalance()>=amount){from.withdraw(amount);// 模拟网络延迟try{Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}to.deposit(amount);}}publicstaticvoidmain(String[]args){Bankbank=newBank();Accountalice=newAccount("Alice",100.0);Accountbob=newAccount("Bob",50.0);// 创建两个线程同时执行转账Threadthread1=newThread(()->{bank.transfer(alice,bob,30.0);});Threadthread2=newThread(()->{bank.transfer(bob,alice,40.0);});thread1.start();thread2.start();}}classAccount{privateStringname;privatedoublebalance;publicAccount(Stringname,doublebalance){this.name=name;this.balance=balance;}publicsynchronizedvoidwithdraw(doubleamount){if(balance>=amount){balance-=amount;System.out.println(name+" withdrew: "+amount);}}publicsynchronizedvoiddeposit(doubleamount){balance+=amount;System.out.println(name+" deposited: "+amount);}publicdoublegetBalance(){returnbalance;}}

问题分析

在上面的代码中,Bank类中的transfer方法是synchronized的,这意味着每次只能有一个线程执行转账操作。然而,这个实现仍然存在一些潜在的问题:

  1. 粒度问题transfer方法对整个转账过程进行了加锁,但实际上只需要对账户的操作进行同步。
  2. 性能瓶颈:如果多个线程频繁调用transfer方法,由于独占锁的存在,可能会导致排队和性能下降。

解决方案

为了优化这个问题,我们可以考虑以下几种方法:

方法一:细化锁粒度

将锁粒度从整个transfer方法降低到具体的账户操作。例如,在Account类中对每个操作进行加锁。

修改后的代码:

publicclassBank{publicvoidtransfer(Accountfrom,Accountto,doubleamount){if(from.getBalance()>=amount){synchronized(from){from.withdraw(amount);}try{Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}synchronized(to){to.deposit(amount);}}}}
方法二:使用更高效的锁机制

在Java中,除了内置的synchronized关键字,还可以使用ReentrantLock来实现更灵活和高效的锁管理。

修改后的代码:

importjava.util.concurrent.locks.ReentrantLock;publicclassBank{privatefinalReentrantLocklock=newReentrantLock();publicvoidtransfer(Accountfrom,Accountto,doubleamount){if(from.getBalance()>=amount){try{// 尝试获取锁,参数为true表示阻塞等待lock.lock();from.withdraw(amount);Thread.sleep(1000);to.deposit(amount);}catch(InterruptedExceptione){e.printStackTrace();}finally{// 释放锁lock.unlock();}}}publicstaticvoidmain(String[]args){Bankbank=newBank();Accountalice=newAccount("Alice",100.0);Accountbob=newAccount("Bob",50.0);Threadthread1=newThread(()->{bank.transfer(alice,bob,30.0);});Threadthread2=newThread(()->{bank.transfer(bob,alice,40.0);});thread1.start();thread2.start();}}

总结

synchronized关键字是Java中实现线程同步的一种简单而有效的方式,但它也有一些局限性。在实际开发中,我们需要根据具体场景选择合适的锁粒度和锁机制,以避免性能瓶颈和潜在的死锁问题。

通过合理使用synchronized方法和其他并发工具(如ReentrantLock),我们可以写出既安全又高效的多线程代码。

📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!

成体系的面试题,无论你是大佬还是小白,都需要一套JAVA体系的面试题,我已经上岸了!你也想上岸吗?

闫工精心准备了程序准备面试?想系统提升技术实力?闫工精心整理了1000+ 套涵盖前端、后端、算法、数据库、操作系统、网络、设计模式等方向的面试真题 + 详细解析,并附赠高频考点总结、简历模板、面经合集等实用资料!

✅ 覆盖大厂高频题型
✅ 按知识点分类,查漏补缺超方便
✅ 持续更新,助你拿下心仪 Offer!

📥免费领取👉 点击这里获取资料

已帮助数千位开发者成功上岸,下一个就是你!✨

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

【Effective Modern C++】第三章 转向现代C++:15. 尽可能使用constexpr

constexpr作用于对象时,是加强版的const;但作用于函数时含义截然不同 —— 它并非简单限定 “返回 const 值” 或 “结果编译期可知”,而是根据调用场景动态适配。 constexpr对象:必然具备const只读属性,且必须由编译期…

作者头像 李华
网站建设 2026/4/23 13:10:25

Java springboot基于微信小程序的漫画小说阅读系统(源码+文档+运行视频+讲解视频)

文章目录 系列文章目录目的前言一、详细视频演示二、项目部分实现截图三、技术栈 后端框架springboot前端框架vue持久层框架MyBaitsPlus微信小程序介绍系统测试 四、代码参考 源码获取 目的 随着移动互联网的普及,漫画小说阅读成为大众喜爱的娱乐方式。本系统基于…

作者头像 李华
网站建设 2026/4/23 13:12:33

基于SpringBoot的定制化设计服务平台系统(源码+lw+部署文档+讲解等)

课题介绍 随着消费升级与个性化需求的崛起,定制化设计服务的市场需求持续增长,但当前行业内存在设计需求与设计师资源对接不畅、服务流程不规范、需求传递不精准、进度跟踪不透明、交易保障不足等问题,既增加了需求方的沟通成本与试错成本&am…

作者头像 李华
网站建设 2026/4/23 13:14:09

基于SpringBoot的建筑工程项目管理系统(源码+lw+部署文档+讲解等)

课题介绍 随着建筑行业的快速发展,建筑工程项目规模不断扩大、流程日益复杂,当前传统的项目管理模式存在流程混乱、信息传递滞后、各部门协同不畅、进度与成本管控不到位、资料归档不规范等问题,既增加了项目管理成本、延长了项目工期&#x…

作者头像 李华
网站建设 2026/4/23 13:16:57

开箱即用!GLM-4.7-Flash镜像详细使用指南

开箱即用!GLM-4.7-Flash镜像详细使用指南 摘要: 你是否经历过这样的场景:下载好大模型,配环境、装依赖、调参数、改配置……折腾两小时,还没打出一句“你好”? GLM-4.7-Flash 镜像不是“又一个需要编译的…

作者头像 李华
网站建设 2026/4/21 12:57:14

5秒克隆音色!IndexTTS 2.0零样本语音合成实战体验

5秒克隆音色!IndexTTS 2.0零样本语音合成实战体验 你有没有过这样的经历:剪完一条30秒的vlog,卡在配音环节整整两小时——找配音员排期、反复调整语速、重录三次还是节奏不对……最后只能凑合用AI合成,结果声音干瘪、情绪平板、像…

作者头像 李华