在 Java 中,synchronized
关键字可以用来修饰实例方法、静态方法或者代码块。当它用于修饰静态方法和普通(实例)方法时,存在一些重要的区别,主要体现在锁的对象以及锁定的范围上。
锁定对象的区别
- 修饰实例方法
- 当
synchronized
用于修饰一个实例方法时,它锁定的是调用该方法的对象实例(即当前对象实例this
)。这意味着每一个对象实例都有其自己的锁,不同实例之间的锁是相互独立的。 - 示例:
public class InstanceSyncExample { public synchronized void instanceMethod() { // 此处的同步块锁定的是当前对象实例 this } }
- 在上面的例子中,如果多个线程试图访问同一个
InstanceSyncExample
实例的instanceMethod()
方法,它们将被串行化执行,因为它们都在竞争同一个实例级别的锁。
但是,如果这些线程操作的是不同的InstanceSyncExample
实例,则每个实例都有自己独立的锁,因此可以并行执行各自的方法。
- 当
- 修饰静态方法
- 当
synchronized
用于修饰静态方法时,它锁定的是该类对应的Class 对象。这是因为静态成员属于类级别而非实例级别,所以静态同步方法使用的锁是整个类的一个单一锁,无论创建了多少个该类的实例,所有实例共享这个锁。 - 示例:
public class StaticSyncExample { public static synchronized void staticMethod() { // 此处的同步块锁定的是 StaticSyncExample 类的 Class 对象 } }
- 在这个例子中,不论有多少个
StaticSyncExample
的实例存在,所有的线程在调用staticMethod()
方法时都会竞争同一个锁,即StaticSyncExample.class
这个锁对象。这意味着即使是从不同的实例调用此静态同步方法,也只能有一个线程能够执行该方法。
- 当
总结
- 锁定对象:
synchronized
修饰实例方法时锁定的是当前对象实例;而修饰静态方法时锁定的是类的 Class 对象。 - 作用范围:对于实例方法,锁定的作用范围限于特定的对象实例;而对于静态方法,锁定的作用范围覆盖了整个类的所有实例。
- 应用场景:如果你需要确保对某个类的所有实例中的某个资源进行同步访问,那么应该使用静态同步方法。反之,如果你只需要保证在同一对象实例内的同步访问,那么使用实例同步方法即可。
了解这两者的区别对于编写高效且正确的并发程序至关重要,尤其是在处理多线程环境下的资源共享问题时。
THE END