Skip to content

synchronized 修饰在类的静态方法上和一个实例方法上有什么区别

约 885 字大约 3 分钟

多线程与并发美团

2025-03-26

⭐ 题目日期:

美团 - 2025/4/4,2024/12/23

📝 题解:

在Java中,synchronized 修饰静态方法和实例方法时,锁的作用范围和锁对象不同,具体区别如下:


1. 锁的作用范围

方法类型锁对象锁的作用范围
静态方法类的 Class 对象所有调用该静态方法的线程(跨实例)
实例方法当前实例(this仅当前实例的同步方法

2. 并发行为示例

(1) 静态方法锁(类锁)

public class MyClass {
    // 静态同步方法
    public static synchronized void staticSyncMethod() {
        // 代码块
    }
}
  • 锁对象MyClass.class
  • 并发表现
    • 所有线程(无论操作哪个实例)调用 staticSyncMethod() 时,会竞争同一把锁
    • 例如,线程A调用 MyClass.staticSyncMethod(),线程B调用 MyClass.staticSyncMethod(),线程B会被阻塞。

(2) 实例方法锁(对象锁)

public class MyClass {
    // 实例同步方法
    public synchronized void instanceSyncMethod() {
        // 代码块
    }
}
  • 锁对象:当前实例(this)。
  • 并发表现
    • 不同实例的 instanceSyncMethod() 互不影响
    • 同一实例的多个同步方法会共享锁
    • 例如,线程A调用 obj1.instanceSyncMethod(),线程B调用 obj2.instanceSyncMethod(),两个线程不会阻塞;但线程B若调用 obj1.instanceSyncMethod(),则会被阻塞。

3. 锁的隔离性

  • 静态方法锁 vs 实例方法锁
    • 静态方法锁(类锁)和实例方法锁(对象锁)互不干扰,因为它们的锁对象不同。
    • 示例:
      public class MyClass {
          public static synchronized void staticSync() {}  // 锁:MyClass.class
          public synchronized void instanceSync() {}       // 锁:this
      }
      • 线程A调用 MyClass.staticSync(),线程B调用 obj.instanceSync()两者不会阻塞

4. 代码验证

(1) 静态方法锁阻塞测试

public class LockTest {
    public static synchronized void staticLock() {
        System.out.println("静态方法加锁");
        try { Thread.sleep(3000); } catch (Exception e) {}
    }

    public static void main(String[] args) {
        new Thread(() -> LockTest.staticLock()).start();
        new Thread(() -> LockTest.staticLock()).start(); // 第二个线程会等待
    }
}

输出

静态方法加锁
(3秒后)
静态方法加锁

(2) 实例方法锁不阻塞测试

public class LockTest {
    public synchronized void instanceLock() {
        System.out.println("实例方法加锁");
        try { Thread.sleep(3000); } catch (Exception e) {}
    }

    public static void main(String[] args) {
        LockTest obj1 = new LockTest();
        LockTest obj2 = new LockTest();
        
        new Thread(() -> obj1.instanceLock()).start();
        new Thread(() -> obj2.instanceLock()).start(); // 第二个线程直接执行
    }
}

输出

实例方法加锁
实例方法加锁
(无等待)

5. 关键总结

维度静态方法锁实例方法锁
锁对象类的 Class 对象当前实例(this
作用范围全局(跨实例)仅当前实例
适用场景保护静态变量或类级别的共享资源保护实例变量或对象级别的共享资源
并发隔离性不同实例的线程会互斥不同实例的线程不会互斥

6. 注意事项

  1. 避免锁混淆
    若在静态方法中同步代码块使用 Class 锁,或在实例方法中同步代码块使用 this 锁,需注意锁对象是否合理。

    // 静态方法中显式使用实例锁(错误!)
    public static void method() {
        synchronized (new MyClass()) { // 无意义,每次锁不同对象
            // ...
        }
    }
  2. 性能影响

    • 静态方法锁(类锁)范围大,可能成为性能瓶颈。
    • 实例方法锁粒度更细,适合高并发场景。

结论

  • 静态方法锁:全局互斥,保护类级别的共享资源。
  • 实例方法锁:实例级互斥,保护对象级别的共享资源。
  • 设计建议:根据资源的作用域选择合适的锁,避免过度同步导致性能下降。