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

Java高频面试之并发编程-18

hello啊,各位观众姥爷们!!!本baby今天又来报道了!哈哈哈哈哈嗝🐶

面试官:详细说说synchronized

synchronized 是 Java 中实现线程同步的核心关键字,用于解决多线程环境下的资源竞争问题,确保线程安全。


1. 基本作用

synchronized 通过 互斥锁(Mutex Lock) 机制,保证同一时刻只有一个线程能访问被保护的代码块或方法,避免多个线程同时操作共享资源导致的数据不一致问题。


2. 使用方式

synchronized 可以修饰以下三种对象:

(1) 实例方法
  • 锁对象:当前实例对象(this)。
  • 作用:同一实例的多个线程会互斥访问该方法。
    public synchronized void method() {// 同步代码
    }
    
(2) 静态方法
  • 锁对象:类的 Class 对象(MyClass.class)。
  • 作用:所有实例的线程都会互斥访问该静态方法。
    public static synchronized void staticMethod() {// 同步代码
    }
    
(3) 代码块
  • 锁对象:显式指定任意对象(通常是共享资源)。
  • 作用:更细粒度地控制同步范围。
    public void blockMethod() {synchronized (lockObject) {  // lockObject 可以是任意对象// 同步代码}
    }
    

3. 核心特性

(1) 可重入性(Reentrant)
  • 同一个线程可以重复获取同一个锁。
  • 示例:线程获取锁后,在同步代码中调用另一个同步方法(使用同一锁)不会阻塞。
(2) 锁的释放
  • 线程执行完同步代码块或方法后,自动释放锁
  • 若线程发生异常退出同步代码块,锁也会自动释放。
(3) 锁的竞争
  • 未获取锁的线程会进入 阻塞状态(BLOCKED),直到锁被释放。

4. 底层原理

synchronized 的底层实现依赖于 JVM 的 Monitor(监视器锁) 机制,具体通过以下步骤实现:

(1) Monitor 对象
  • 每个 Java 对象都与一个 Monitor 关联,Monitor 包含以下关键字段:
    • _owner:记录当前持有锁的线程。
    • _EntryList:等待获取锁的阻塞线程队列。
    • _WaitSet:调用 wait() 后进入等待状态的线程队列。
(2) 字节码层面
  • 同步代码块通过 monitorentermonitorexit 指令实现:
    public void method() {synchronized (obj) {// 代码}
    }
    
    对应的字节码:
    monitorenter   // 尝试获取锁
    ...             // 同步代码
    monitorexit    // 释放锁
    
(3) 锁升级优化(JDK 1.6+)

为了提高性能,JVM 对 synchronized 进行了优化,引入了 锁升级机制

  1. 无锁(No Lock):初始状态。
  2. 偏向锁(Biased Lock):锁偏向第一个获取它的线程,避免后续 CAS 操作。
  3. 轻量级锁(Lightweight Lock):通过 CAS 自旋尝试获取锁,避免线程阻塞。
  4. 重量级锁(Heavyweight Lock):竞争激烈时,升级为操作系统级别的互斥锁(Mutex)。

5. 典型应用场景

(1) 线程安全的单例模式
public class Singleton {private static volatile Singleton instance;public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}
(2) 保护共享资源
public class Counter {private int count = 0;public synchronized void increment() {count++;}
}

6. 与 ReentrantLock 的对比

特性synchronizedReentrantLock
锁类型JVM 内置锁JDK 实现的显式锁
灵活性不支持中断、超时、公平锁支持中断、超时、公平锁
代码控制自动释放锁需手动 lock()unlock()
性能JDK 1.6 后优化,性能接近显式锁高竞争场景下性能更好
适用场景简单同步需求复杂同步逻辑(如条件变量 Condition

7. 注意事项

  1. 锁对象的选择

    • 避免使用字符串常量或基本类型(如 Integer)作为锁对象。
    • 推荐使用私有、不可变的对象:private final Object lock = new Object();
  2. 减少同步范围

    • 尽量缩小同步代码块,避免在同步块内执行耗时操作(如 I/O)。
  3. 死锁风险

    • 避免嵌套锁或多锁顺序不一致导致的死锁。
    • 示例:线程 A 先锁 X 再锁 Y,线程 B 先锁 Y 再锁 X → 可能死锁。
  4. 锁粗化与锁消除

    • 锁粗化:JVM 将多个连续锁合并为一个锁,减少开销。
    • 锁消除:JVM 检测到不可能存在共享竞争时,自动去除锁(如局部变量)。

8. 常见问题

Q1:synchronizedvolatile 的区别?
  • synchronized:保证原子性、可见性和有序性。
  • volatile:仅保证可见性和有序性,不保证原子性(如 i++ 仍需同步)。
Q2:静态方法和实例方法的锁是否冲突?
  • 不冲突!静态方法锁的是类对象(Class),实例方法锁的是当前实例(this)。
Q3:如何排查死锁?
  • 使用 jstack 或可视化工具(如 JConsole)查看线程状态和锁持有情况。

总结

synchronized 是 Java 线程同步的基石,通过 Monitor 机制实现互斥访问。虽然在高并发场景下可能成为性能瓶颈,但其简洁性和 JVM 的优化(如锁升级)使其在大多数场景下足够高效。对于更复杂的同步需求,可结合 ReentrantLock 或并发工具类(如 SemaphoreCountDownLatch)使用。

在这里插入图片描述

相关文章:

  • 五分钟本地部署大模型
  • “星睿O6”AI PC 开发套件评测: NPU 算力测评(1)
  • MySQL 锁机制深度剖析:全局锁、表锁与行锁
  • 如何从容应对面试?
  • 大模型小课堂开课啦!!!
  • yolo模型优化【上下文标注】
  • HJ3 明明的随机数【牛客网】
  • 常见提示词攻击方法和防御手段——提示词越狱
  • 同一颗太阳:Australia、Austria、Arab、Africa、Augustus、August、Aurora、Athena
  • LeetCode 1306. 跳跃游戏 III(中等)
  • 网络-MOXA设备基本操作
  • Python测试单例模式
  • ubuntu系统 | dify+ollama+deepseek搭建本地应用
  • gcc: attribute: packed
  • FEKO许可证与多用户共享
  • day 21 常见降维算法
  • CPP之动态内存管理以及模板初阶
  • 第三十九节:视频处理-光流法 (Lucas-Kanade, Dense)
  • 计算机存储与数据单位的核心定义及换算逻辑
  • 深度解析 MCP:重新定义 API 的开发范式
  • 解读|俄方称愿与乌方共同起草和平备忘录,特朗普多轮通话外交有效吗?
  • 李公明 | 一周画记:德里达哲学还是接地气的
  • 从《缶翁的世界》看吴昌硕等湖州籍书画家对海派的影响
  • 上博东馆常设陈列入选全国博物馆“十大精品”
  • 人民网:激发博物馆创新活力,让“过去”拥有“未来”
  • 赡养纠纷个案推动类案监督,检察机关保障特殊群体胜诉权