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

Java面试必看:同步方法和同步块到底该选哪个?

文章目录

  • Java面试必看:同步方法和同步块到底该选哪个?
    • 前言
    • 第一部分:同步方法是什么?
      • 示例代码:同步方法
    • 第二部分:同步块是什么?
      • 示例代码:同步块
    • 第三部分:同步方法和同步块有什么区别?
      • 1. 锁的范围不同
      • 2. 锁的对象不同
      • 3. 性能上的区别
    • 第四部分:到底该选哪个?
      • 1. 情况一:整个方法都需要同步
      • 2. 情况二:部分代码需要同步
      • 3. 情况三:多个方法使用同一个锁
    • 第五部分:实际开发中的小技巧
      • 技巧一:避免使用`Object.class`作为锁
      • 技巧二:尽量避免同步方法
      • 技巧三:使用`ReentrantLock`代替内置锁
    • 总结
    • 在实际开发中,尽量根据具体需求选择合适的同步方式,并结合`ReentrantLock`等高级工具来提升代码的灵活性和性能。
      • 📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!

Java面试必看:同步方法和同步块到底该选哪个?

前言

大家好,我是闫工。今天咱们要聊一个在Java多线程编程中非常重要的问题——同步方法和同步块到底该怎么选?

作为一个有多年开发经验的老码农,我见过太多面试官问这个问题了。很多同学一看到这个问题就懵了,不知道该怎么回答。其实啊,这个问题不难,只要搞清楚它们的原理和适用场景,自然就能应对自如了。

今天我就来手把手教大家如何理解和选择同步方法与同步块。咱们不仅要有理论,还要有代码示例,更要有一些实际开发中的小技巧。话不多说,咱们开始吧!


第一部分:同步方法是什么?

首先,咱们得明白什么是同步方法(Synchronized Method)。

在Java中,同步方法就是在方法前面加上public synchronized void method()这样的关键字。它的作用是确保同一时间只有一个线程可以执行这个方法。简单来说,就是当一个线程进入这个方法后,其他线程必须等待,直到当前线程退出该方法才能继续执行。

示例代码:同步方法

publicclassSynchronizedMethodExample{privateintcount=0;publicsynchronizedvoidincrement(){count++;System.out.println("Current count: "+count);}publicstaticvoidmain(String[]args){SynchronizedMethodExampleexample=newSynchronizedMethodExample();Runnabletask=()->{for(inti=0;i<5;i++){example.increment();}};Threadthread1=newThread(task);Threadthread2=newThread(task);thread1.start();thread2.start();}}

运行结果:

Current count: 1 Current count: 2 Current count: 3 Current count: 4 Current count: 5 Current count: 6 Current count: 7 Current count: 8 Current count: 9 Current count: 10

解释:

  • 在上面的代码中,increment()方法被声明为同步方法。
  • 当两个线程同时调用这个方法时,它们会被“排队”,一个接一个地执行,确保计数器不会出现错误。

第二部分:同步块是什么?

接下来,咱们来看看同步块(Synchronized Block)

同步块的作用和同步方法类似,但它更加灵活。你可以在代码中选择任意一块需要被同步的代码,并且可以指定不同的锁对象。

示例代码:同步块

publicclassSynchronizedBlockExample{privateintcount=0;publicvoidincrement(){synchronized(this){// 使用当前实例作为锁count++;System.out.println("Current count: "+count);}}publicstaticvoidmain(String[]args){SynchronizedBlockExampleexample=newSynchronizedBlockExample();Runnabletask=()->{for(inti=0;i<5;i++){example.increment();}};Threadthread1=newThread(task);Threadthread2=newThread(task);thread1.start();thread2.start();}}

运行结果:

Current count: 1 Current count: 2 Current count: 3 Current count: 4 Current count: 5 Current count: 6 Current count: 7 Current count: 8 Current count: 9 Current count: 10

解释:

  • 在上面的代码中,increment()方法并没有被声明为同步方法。
  • 而是在方法内部使用了synchornized (this)块来实现同步,锁的对象是当前实例this

第三部分:同步方法和同步块有什么区别?

现在咱们已经了解了什么是同步方法和同步块,接下来要解决的核心问题是:它们到底有什么区别?

1. 锁的范围不同

  • 同步方法:

    • 锁的范围是整个方法。
    • 只有在进入这个方法时才会加锁,离开该方法时自动释放锁。
  • 同步块:

    • 锁的范围可以是任意代码块。
    • 可以根据需要选择加锁和释放锁的位置,更加灵活。

2. 锁的对象不同

  • 同步方法:

    • 如果方法是实例方法(非静态),那么默认锁对象是this
    • 如果方法是静态方法,则锁对象是这个类的Class对象。
  • 同步块:

    • 可以指定任意对象作为锁,比如this、某个类或自定义对象。

3. 性能上的区别

  • 同步方法:

    • 因为整个方法都被锁住,可能会导致性能问题。
    • 如果一个方法中只有部分代码需要同步,其余代码也被锁住,浪费资源。
  • 同步块:

    • 只锁住需要的部分,减少了不必要的锁竞争,提升了性能。

第四部分:到底该选哪个?

那么问题来了,在实际开发中该怎么选择呢?

1. 情况一:整个方法都需要同步

如果一个方法的所有代码都需要被同步,那么直接使用同步方法会更加简洁明了。因为这样可以避免在方法内部写额外的锁控制代码。

示例代码:

publicsynchronizedvoidallNeedSync(){// 整个方法都加锁}

2. 情况二:部分代码需要同步

如果只有方法中的一部分代码需要被同步,那么使用同步块会更加高效。因为这样可以避免将整个方法都锁住。

示例代码:

publicvoidonlyPartNeedSync(){// 需要被同步的代码synchronized(this){// 只有这部分加锁}// 不需要被同步的代码}

3. 情况三:多个方法使用同一个锁

有时候,我们需要在不同的方法中使用同一个锁对象。这时候,可以使用同步块,并指定相同的锁对象。

示例代码:

publicclassMultiMethodSync{privateObjectlock=newObject();publicvoidmethod1(){synchronized(lock){// 使用自定义的锁对象// 代码逻辑}}publicvoidmethod2(){synchronized(lock){// 使用同一个锁对象// 代码逻辑}}}

第五部分:实际开发中的小技巧

技巧一:避免使用Object.class作为锁

有些同学可能会直接用Object.class作为同步块的锁对象。比如:

synchronized(Object.class){// 代码逻辑}

这样做非常危险,因为Object.class是所有Java类的父类,如果其他代码也用了这个锁,会导致全局锁竞争,严重影响性能。

正确做法:

  • 使用当前实例this作为锁。
  • 或者定义一个专门的锁对象。

技巧二:尽量避免同步方法

虽然在某些情况下使用同步方法很方便,但它的粒度太大。如果整个方法并不都需要被同步,最好还是改用同步块。

示例代码:

publicvoidmethod(){// 不需要加锁的代码synchronized(this){// 只有部分代码加锁// 需要加锁的代码}// 不需要加锁的代码}

技巧三:使用ReentrantLock代替内置锁

Java提供了一个更强大的锁机制——ReentrantLock,它可以替代内置的synchronized关键字。

优点:

  • 更灵活的锁控制。
  • 支持公平锁、非公平锁等高级功能。

示例代码:

importjava.util.concurrent.locks.ReentrantLock;publicclassReentrantLockExample{privatefinalReentrantLocklock=newReentrantLock();publicvoidmethod(){try{lock.lock();// 加锁// 需要被同步的代码}finally{lock.unlock();// 释放锁}}}

总结

  • 同步方法:适合整个方法都需要被同步的情况。
  • 同步块:更适合部分代码需要同步,或者多个方法共享同一个锁的情况。

在实际开发中,尽量根据具体需求选择合适的同步方式,并结合ReentrantLock等高级工具来提升代码的灵活性和性能。

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

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

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

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

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

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

http://www.jsqmd.com/news/165540/

相关文章:

  • 谁懂啊!2026 转行网安太香了!480 万缺口 + 15K 起薪,薪资 + 工作内容 + 前景全解析!
  • 港大联合字节跳动提出JoVA:一种基于联合自注意力的视频-音频联合生成模型
  • 基于昇腾910B的文生图模型推理服务化部署
  • python基于Vue的农机配件仓库管理系统的设计与实现_56d42_django Flask pycharm项目
  • python基于Vue的减肥体脂健康运动健身器材管理系统的设计与实现_5m179_django Flask pycharm项目
  • debian 与 ubuntu 之 - sudo
  • 在线互动学习网站设计毕业论文+PPT(附源代码+演示视频)
  • 还在熬夜赶论文?7款AI神器帮你选题降重一站式搞定!
  • 油泵轴承厂家推荐榜单 油泵电机/液压泵/电缸/7308/7309/73010/7311/7305/7306/7313/7315长寿命轴承制造商推荐 - 小张666
  • python基于Vue的培训机构在线教育教学平台设计与实现_pff2s_django Flask pycharm项目
  • python基于Vue的客户关系订单服务管理系统设计与实现_37g31_django Flask pycharm项目
  • python基于Vue的拍卖管理系统设计与实现_django Flask pycharm项目
  • Git命令大全:一表掌握所有核心操作
  • python基于Vue的汽车4s店销售一体化服务管理系统的设计与实现_6fc7t_django Flask pycharm项目
  • 锚定2026:易方达 A500ETF(159361)卡位领先,资金与规模双双站稳头部 - 速递信息
  • python基于Vue的家装一体化装修商城平台_guptn_django Flask pycharm项目
  • :has 伪类选择器(“父选择器” 或 “反向选择器” )
  • python基于Vue的快递业务配送取件管理系统_gbu3f_django Flask pycharm项目
  • python基于Vue的汽配汽车配件销售采购管理系统_23cu0_django Flask pycharm项目
  • (网警vs顶级黑客)网络攻防的核心底层逻辑
  • python基于Vue的教务选课缴费管理系统_ux52l_django Flask pycharm项目
  • 富文本编辑器粘贴Word公式转图片的组件
  • python基于Vue的洛川县苹果销售水果农产品商城管理平台_3tzoe_django Flask pycharm项目
  • 【博客之星】2025年度创作成长总结 - 高层次综合设计,和我一道,要识庐山真面目
  • 网页编辑器Word图片自动转Base64上传组件
  • Rime-AI v2版本发布
  • python基于Vue的民宿客房预约管理系统的设计与实现_16605_django Flask pycharm项目
  • 角度头轴承重点厂家推荐 角度头/侧铣头/直角铣头/万能铣头/动力刀座/高精度精密主轴轴承厂家选择指南 - 小张666
  • HTML富文本编辑器粘贴PPT图片自动上传组件
  • SpringBoot + MyBatis-Plus + Redis + RabbitMQ:电商秒杀场景下的库存预扣与订单异步创建​