Java的synchronized:从入门到“秃头”的终极指南

Java的synchronized:从入门到"秃头"的终极指南


一、介绍:synchronized是什么?

synchronized是Java中的"保安大哥",专门负责在多线程环境下维持秩序,确保共享资源不被"哄抢"。它的核心使命是解决线程安全问题,保证原子性(操作不可分割)、可见性(修改立即可见)和有序性(代码顺序执行)。

为什么需要它?

想象两个线程同时修改银行账户余额,如果没有同步机制,结果可能像两个人在同一张纸上乱涂乱画,最终余额变成谜团。而synchronized会大喊:"排好队,一个一个来!"。


二、用法:三种姿势,总有一款适合你

  1. 修饰实例方法

    锁住当前对象实例,适用于保护对象级别的共享资源。

    java 复制代码
    public synchronized void transferMoney() { /* 转账逻辑 */ }
  2. 修饰静态方法

    锁住整个类,适用于保护类级别的静态资源。

    java 复制代码
    public static synchronized void updateConfig() { /* 更新全局配置 */ }
  3. 修饰代码块

    灵活指定锁对象,适合只保护部分代码的场景。

    java 复制代码
    public void addToCart() {
        synchronized (cartLock) { /* 加购逻辑 */ }
    }

    注意 :别用String或基本类型包装类当锁,容易踩坑(比如字符串常量池的缓存问题)。


三、案例:代码中的"锁"事剧场

场景1 :普通方法同步

两个线程调用同一个对象的同步方法,结果像排队上厕所------必须等前一个人出来。

场景2 :静态方法同步

即使创建了多个对象实例,静态方法同步也会锁住整个类,相当于"全店打烊,只服务一个人"。

场景3 :代码块同步

只锁住关键代码,其他代码自由飞翔,性能和安全性兼得。


四、原理:锁的"变形记"

从Java 6开始,synchronized开启了"智能模式",根据竞争激烈程度自动升级锁状态:

  1. 无锁:对象刚出生,人畜无害。
  2. 偏向锁:假设只有一个线程访问,直接在对象头贴个"VIP标签"(线程ID),省去加锁步骤。
  3. 轻量级锁:多个线程交替访问,通过CAS自旋(像在锁门口徘徊)尝试获取锁,避免阻塞。
  4. 重量级锁:竞争激烈时,召唤操作系统级互斥量,线程排队等叫号,性能开销大但公平。

锁升级的目的:像饭店老板根据客流量调整服务员数量,既省成本又保效率。


五、对比:synchronized vs 其他同步工具

  1. synchronized vs volatile

    • volatile只管可见性,不保原子性(比如i++仍需同步)。
    • synchronized是"全能选手",但可能引发线程阻塞。
  2. synchronized vs ReentrantLock

    • synchronized自动释放锁,ReentrantLock需手动unlock()(忘写就死锁警告!)。
    • ReentrantLock支持可中断、公平锁、多条件变量,适合复杂场景。

六、避坑指南:别让锁"锁"住你的智商

  1. 不完全同步

    java 复制代码
    // set方法同步,get方法不同步 → 可能读到旧值!
    public synchronized void setX(int x) { this.x = x; }
    public int getX() { return x; } // 应加synchronized或用volatile
  2. 锁对象中途变心

    java 复制代码
    synchronized (array[0]) { 
        array[0] = new Object(); // 锁对象被替换,同步失效!
    }
  3. 在循环中滥用锁

    频繁加锁会导致性能"雪崩",改用原子类(如AtomicInteger)或并发集合更香。


七、最佳实践:做个锁的"时间管理大师"

  1. 锁粒度要细:只锁必要代码,像只保护保险箱而不是整个房间。
  2. 用final对象当锁:防止锁对象被意外替换。
  3. 避免嵌套锁:小心死锁,像两个人互相等对方先放手。
  4. 优先选代码块:比锁方法更灵活,减少阻塞范围。

八、面试考点:高频灵魂拷问

  1. 锁升级过程(偏向锁→轻量级锁→重量级锁)。
  2. synchronized和ReentrantLock的区别(自动vs手动、功能扩展性)。
  3. 为什么synchronized是非公平锁
    (答:唤醒线程随机,插队更高效,但可能"饿死"老实线程)。

九、总结:synchronized的"人生哲学"

  • 优点:简单易用、自动释放、可重入。
  • 缺点:无法中断、不支持超时、非公平。
  • 适用场景 :低竞争或简单同步需求;高竞争时考虑ReentrantLockStampedLock

最后提醒:锁虽好,但别滥用!多线程编程就像开车,安全第一,性能第二。


参考资料

(想要更深入细节?点击链接直达原文,开启"秃头"之旅吧!)

相关推荐
Moss Huang5 小时前
docker-runc not installed on system
java·docker·容器
麦兜*7 小时前
Spring Boot 集成 Docker 构建与发版完整指南
java·spring boot·后端·spring·docker·系统架构·springcloud
Cisyam^7 小时前
Go环境搭建实战:告别Java环境配置的复杂
java·开发语言·golang
CHENFU_JAVA7 小时前
使用EasyExcel实现Excel单元格保护:自由锁定表头和数据行
java·excel
青云交8 小时前
Java 大视界 -- 基于 Java 的大数据实时流处理在智能电网分布式电源接入与电力系统稳定性维护中的应用(404)
java·大数据·分布式·智能电网·flink 实时流处理·kafka 数据采集·iec 61850 协议
仰望星空@脚踏实地9 小时前
maven scope 详解
java·maven·scope
M_Reus_119 小时前
Groovy集合常用简洁语法
java·开发语言·windows
带刺的坐椅9 小时前
10分钟带你体验 Solon 的状态机
java·solon·状态机·statemachine
小鹅叻9 小时前
MyBatis题
java·tomcat·mybatis