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

保姆级教程:synchronized 同步方法 vs 同步代码块,看完彻底懂锁!

一、同步方法(锁住整个方法)

1. 代码示例
public class Counter {
    private int count = 0;

    // 同步方法:锁住整个方法
    public synchronized void add() {
        count++;
    }

    // 同步方法:锁住整个方法
    public synchronized void subtract() {
        count--;
    }
}
2. 原理
  • 锁对象synchronized 修饰普通方法时,锁的是当前对象(this)。
  • 锁范围:整个方法体被锁定,其他线程无法访问该对象的任何同步方法。
3. 生活比喻

假设有一个 超市储物柜管理员

  • 管理员一次只能服务一个人(同步方法)。
  • 当你在存包时(调用 add 方法),其他人不能存包也不能取包(调用任何同步方法)。

二、同步代码块(锁住部分代码)

1. 代码示例
public class Counter {
    private int count = 0;
    private final Object lock = new Object(); // 自定义锁对象

    public void add() {
        // 非同步代码(可并发执行)
        System.out.println("处理存包请求...");
        
        // 同步代码块:锁住关键部分
        synchronized(lock) {
            count++;
        }
    }

    public void subtract() {
        // 非同步代码(可并发执行)
        System.out.println("处理取包请求...");
        
        // 同步代码块:锁住关键部分
        synchronized(lock) {
            count--;
        }
    }
}
2. 原理
  • 锁对象:可以指定任意对象(如 lockthis)。
  • 锁范围:只锁定代码块内部,其他代码可并发执行。
3. 生活比喻

同一个 超市储物柜管理员

  • 管理员的大部分工作是协调(非同步代码),比如回答顾客问题。
  • 只有开柜子存取物品时(同步代码块) 需要独占操作,其他时间可以处理其他请求。

三、关键区别总结

特性同步方法同步代码块
锁对象默认是 this(对象锁)可自由指定(更灵活)
锁粒度粗粒度(整个方法)细粒度(仅关键代码)
性能较低(锁范围大,竞争多)较高(锁范围小,竞争少)
适用场景简单逻辑,方法整体需要保护需要精细化控制锁的代码段

四、实际开发中的选择建议

1. 优先用同步代码块
  • 原因:缩小锁范围,提高并发效率。
  • 场景:方法中只有部分代码涉及共享资源操作。
    public void transfer(Account target, int amount) {
        // 非同步代码(比如日志记录)
        log("转账操作开始...");
        
        // 同步代码块(锁定两个账户)
        synchronized(this) {
            synchronized(target) {
                this.balance -= amount;
                target.balance += amount;
            }
        }
    }
    
2. 同步方法的适用场景
  • 简单场景:整个方法都需要保护,且逻辑简单。
    public synchronized void reset() {
        // 重置所有数据
        this.balance = 0;
        this.transactionCount = 0;
    }
    
3. 避免的陷阱
  • 错误示例:在同步方法中调用另一个同步方法。
    public synchronized void methodA() {
        methodB(); // 如果 methodB 也是同步方法,会导致锁重入(允许,但需注意设计)
    }
    
    public synchronized void methodB() {
        // ...
    }
    
    • 锁重入:Java 允许同一个线程重复获取已持有的锁,但要避免过度嵌套。

五、扩展知识:锁对象的选择

  • 建议自定义锁:避免直接使用 this 或类对象(ClassName.class),防止与其他代码冲突。
    private final Object dataLock = new Object(); // 专用锁对象
    
    public void updateData() {
        synchronized(dataLock) { 
            // 操作共享数据
        }
    }
    

总结

  • 同步方法:简单粗暴,适合保护整个方法。
  • 同步代码块:灵活高效,适合精细化控制。
    核心思想:用最小的锁范围,实现线程安全,同时最大化并发性能!

相关文章:

  • QML-项目实战二
  • Ubuntu Live USB 如何使用
  • 《深度洞察:MySQL与Oracle中游标的性能分野》
  • 重新排序--区间问题--差分求频率,全开ll
  • 静态路由复习实验
  • MyBatis-Plus逆向工程
  • ORM框架
  • SQL Server安装后 SSMS 无法连接:身份验证模式错误
  • 可编辑36页PPT | “新基建”在数字化智慧高速公路中的支撑应用方案智慧高速解决方案智慧交通方案
  • 《C奥林匹斯宝典:基础篇 - 重载函数》
  • 机器人传感器系统---时间戳对齐
  • vue使用markdown-it-katex部分公式展示不正确 katex版本低
  • 深度学习--softmax回归
  • 基于TradingView和CTPBee的自动化期货交易系统实现
  • Saas产品性能优化实战
  • bluecode-字符替换与最长子串问题
  • 【开题报告+论文+源码】基于SpringBoot+Vue的乡村公共资源管理系统
  • VS Code查看html格式文件插件:Live Server、HTML Preview
  • 多个SVN版本库,共用同一个和密码配置文件
  • Nacos 配置信息的发布流程是怎样的?服务端是如何校验和处理这些信息的?
  • 国家统计局:2024年城镇单位就业人员工资平稳增长
  • 雷军内部演讲回应质疑:在不服输、打不倒方面,没人比我们更有耐心
  • 讲座预告|以危机为视角解读全球治理
  • 4月企业新发放贷款利率处于历史低位
  • 陕西一村民被冒名贷款40余万续:名下已无贷款,将继续追责
  • 从《让·桑特伊》到《追忆》,假故事的胜利