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

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


参考资料

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

相关推荐
yuluo_YX8 小时前
Reactive 编程 - Java Reactor
java·python·apache
山岚的运维笔记8 小时前
SQL Server笔记 -- 第20章:TRY/CATCH
java·数据库·笔记·sql·microsoft·sqlserver
南极企鹅9 小时前
springBoot项目有几个端口
java·spring boot·后端
清风拂山岗 明月照大江9 小时前
Redis笔记汇总
java·redis·缓存
xiaoxue..9 小时前
合并两个升序链表 与 合并k个升序链表
java·javascript·数据结构·链表·面试
忧郁的Mr.Li9 小时前
SpringBoot中实现多数据源配置
java·spring boot·后端
yq19820430115610 小时前
静思书屋:基于Java Web技术栈构建高性能图书信息平台实践
java·开发语言·前端
一个public的class10 小时前
你在浏览器输入一个网址,到底发生了什么?
java·开发语言·javascript
有位神秘人10 小时前
kotlin与Java中的单例模式总结
java·单例模式·kotlin
golang学习记10 小时前
IntelliJ IDEA 2025.3 重磅发布:K2 模式全面接管 Kotlin —— 告别 K1,性能飙升 40%!
java·kotlin·intellij-idea