news 2026/4/16 2:17:26

Java面试必懂!深入解析synchronized关键字的用法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java面试必懂!深入解析synchronized关键字的用法

文章目录

  • Java面试必懂!深入解析synchronized关键字的用法 ?
    • 一、什么是`synchronized`?
    • 二、`synchronized`的使用方式
      • 1. `synchronized`修饰实例方法
      • 2. `synchronized`修饰静态方法
      • 3. `synchronized`修饰代码块
      • 4. `synchronized`的关键点
    • 三、`synchronized`的优缺点
      • 优点
      • 缺点
    • 四、面试常见问题
      • 1. `synchronized`和`ReentrantLock`有什么区别?
      • 2. `synchronized`为什么会引起死锁?
      • 3. 如何避免死锁?
      • 4. `synchronized`和`volatile`有什么区别?
    • 五、实战案例
    • 六、总结
    • `
      • 📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!

Java面试必懂!深入解析synchronized关键字的用法 ?

大家好,我是闫工!今天呢,咱们来聊一个Java面试中绝对绕不开的话题——synchronized关键字。作为一个在Java世界里摸爬滚打多年的“老码农”,我得告诉你们,这个知识点可是线程安全领域的“老祖宗”了。不管是初学还是进阶,掌握它都是你通向高薪offer的必经之路!所以,咱们今天就从基础到高级,再到面试中可能会被问到的各种细节,来一场彻底的解析!


一、什么是synchronized

简单来说,synchronized关键字是用来保证线程安全的。在线程并发的情况下,多个线程同时操作共享资源时,容易出现“脏数据”或者“竞态条件”,这时候就需要用sync来加把锁,让代码块或方法变成“临界区”,每次只能有一个线程进入执行。

听起来有点抽象?没关系,咱们先来看一个经典的例子:银行转账问题。假设A和B两个人同时给C转账100元,那么如果不做任何处理,可能会出现这样的情况:

publicclassBank{privateintbalance=0;publicvoiddeposit(intamount){balance+=amount;// 这里可能有竞态条件!}publicstaticvoidmain(String[]args){Bankbank=newBank();Threadt1=newThread(()->bank.deposit(100));Threadt2=newThread(()->bank.deposit(100));t1.start();t2.start();}}

上面的代码中,deposit方法没有加锁,所以A和B可能同时读取到balance=0,然后都执行balance += 100,结果就是balance变成100而不是200。这就是线程不安全的表现。

那怎么解决呢?很简单,给deposit加上synchronized

publicsynchronizedvoiddeposit(intamount){balance+=amount;}

这样,每次只有一个线程能执行这个方法,问题就解决了!


二、synchronized的使用方式

1.synchronized修饰实例方法

这是最常见的用法。当一个实例方法被synchronized修饰时,锁的对象是调用该方法的那个具体实例(也就是this)。例如:

publicclassCounter{privateintcount=0;publicsynchronizedvoidincrement(){count++;}}

这样,在同一时间只有一个线程可以执行increment()方法。

2.synchronized修饰静态方法

有时候,我们需要对静态方法加锁。比如,一个类级别的计数器:

publicclassStaticCounter{privatestaticintcount=0;publicsynchronizedstaticvoidincrement(){count++;}}

这时候,锁的对象是这个类的Class对象(StaticCounter.class),所以不管有多少个实例,静态方法只有一个共享的锁。

3.synchronized修饰代码块

有时候我们不需要对整个方法加锁,只需要对一部分代码加锁。这时可以用synchronized包裹一个代码块:

publicclassThreadSafeBank{privateintbalance;publicvoidtransfer(intfromAccountId,inttoAccountId,intamount){synchronized(fromAccountId){// 锁住fromAccountId// 执行转账逻辑...}synchronized(toAccountId){// 锁住toAccountId// ...}}}

这样,可以更灵活地控制锁的范围。

4.synchronized的关键点

  • 锁的对象:无论是方法还是代码块,synchronized都是基于对象来加锁的。实例方法用this,静态方法用Class对象,代码块可以用任意对象。
  • 可重入性:同一个线程可以多次获取同一个锁,而不会死锁。比如,一个线程调用了synchronized方法A,然后在方法A里又调用了另一个synchronized方法B,这时候JVM会知道是同一线程,允许进入。

三、synchronized的优缺点

优点

  1. 简单直接:使用起来非常直观,几乎不需要额外配置。
  2. 内置支持:JDK原生支持,不需要引入第三方库。

缺点

  1. 性能问题:在高并发场景下,synchronized的粒度可能太大,导致线程 contention(争用),影响性能。
  2. 灵活性不足:只能提供粗粒度的锁控制,无法像ReentrantLock那样支持公平锁、可中断锁等高级特性。

四、面试常见问题

1.synchronizedReentrantLock有什么区别?

  • 语法层面synchronized是关键字,语法糖;而ReentrantLock是一个类,需要显式调用方法。
  • 功能层面ReentrantLock提供了更多的灵活性,比如支持公平锁、可中断锁等,但使用起来也更复杂。

2.synchronized为什么会引起死锁?

当两个线程互相等待对方释放锁时就会发生死锁。例如:

publicclassDeadlockExample{publicstaticvoidmain(String[]args){Threadt1=newThread(()->{synchronized(String.class){// 锁Atry{Thread.sleep(100);}catch(InterruptedExceptione){}synchronized(Integer.class){// 锁BSystem.out.println("Thread 1 done");}}});Threadt2=newThread(()->{synchronized(Integer.class){// 锁Btry{Thread.sleep(100);}catch(InterruptedExceptione){}synchronized(String.class){// 锁ASystem.out.println("Thread 2 done");}}});t1.start();t2.start();}}

如果t1先拿到锁A,而t2先拿到锁B,那么两个线程都会卡在等待对方释放锁的状态,导致死锁。

3. 如何避免死锁?

  • 按顺序加锁:所有线程都按照固定的顺序获取锁。
  • 使用tryLock()方法:如果无法立即获得锁,则不阻塞当前线程,而是返回一个布尔值表示是否成功。

4.synchronizedvolatile有什么区别?

  • 作用synchronized是关于多线程的互斥与同步;而volatile是关于内存可见性。
  • 粒度synchronized可以控制一段代码块或方法,而volatile只能修饰变量。

五、实战案例

假设我们有一个共享资源池,需要确保每次只有一个线程能获取资源。这时候可以用synchronized来实现:

publicclassResourcePool{privateObjectresource;publicsynchronizedvoidgetResource(){if(resource==null){// 模拟资源加载try{Thread.sleep(100);}catch(InterruptedExceptione){}resource=newObject();System.out.println("Resource created by "+Thread.currentThread().getName());}}publicstaticvoidmain(String[]args){ResourcePoolpool=newResourcePool();Runnabletask=()->pool.getResource();for(inti=0;i<10;i++){newThread(task,"Thread-"+i).start();}}}

这样,所有线程都会排队等待获取锁,从而保证资源只被创建一次。


六、总结

`

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

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

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

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

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

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

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

零基础玩转FLUX.1-dev:赛博朋克WebUI+显存优化全攻略

零基础玩转FLUX.1-dev&#xff1a;赛博朋克WebUI显存优化全攻略 在RTX 4090D成为创作主力却仍被“CUDA Out of Memory”反复打断的今天&#xff0c;一个更现实的问题浮出水面&#xff1a;为什么我们手握24GB显存&#xff0c;却还要为每张图手动清缓存、调步数、关预览&#xff…

作者头像 李华
网站建设 2026/4/11 15:31:47

Qwen3-Embedding-4B实操案例:API文档语义搜索替代传统TOC导航

Qwen3-Embedding-4B实操案例&#xff1a;API文档语义搜索替代传统TOC导航 1. 为什么你需要语义搜索&#xff0c;而不是目录跳转&#xff1f; 翻过几十页API文档&#xff0c;只为找一个叫“get_user_profile_v2”的接口&#xff1f; 在Swagger页面里反复滚动、CtrlF输入“toke…

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

Nano-Banana快速上手:设计师常用10组Knolling/Exploded Prompt模板

Nano-Banana快速上手&#xff1a;设计师常用10组Knolling/Exploded Prompt模板 1. 认识Nano-Banana Studio Nano-Banana Studio是一款基于SDXL模型的AI创作工具&#xff0c;专门用于生成工业级的产品平铺图(Knolling)和分解视图(Exploded View)。它能将复杂的物品如服装、鞋包…

作者头像 李华
网站建设 2026/4/12 7:32:19

DeerFlow快速上手:5分钟搭建你的AI研究助理

DeerFlow快速上手&#xff1a;5分钟搭建你的AI研究助理 1. 这不是另一个聊天机器人&#xff0c;而是一个会主动思考的研究搭档 你有没有过这样的经历&#xff1a;想深入研究一个技术趋势&#xff0c;却卡在信息收集环节——要查论文、翻新闻、看社区讨论、跑代码验证&#xff0…

作者头像 李华
网站建设 2026/4/5 13:56:30

GTE-Chinese-Large部署案例:制造业设备维修手册语义检索系统落地

GTE-Chinese-Large部署案例&#xff1a;制造业设备维修手册语义检索系统落地 在传统制造业中&#xff0c;一线维修工程师常常面临一个现实困境&#xff1a;面对几十本、上百页的设备维修手册PDF&#xff0c;当设备突发故障时&#xff0c;需要快速定位“液压系统压力异常”“伺…

作者头像 李华