在Java中,synchronized关键字是一个非常重要的同步机制,它可以用来修饰方法或代码块,以确保在同一时刻最多只有一个线程可以执行某个方法或代码块。synchronized修饰静态方法和非静态方法时,其作用范围和行为是有所不同的。
-
修饰非静态方法: 当
synchronized修饰一个非静态方法时,它实际上是对调用该方法的对象实例加锁(也称为对象锁或实例锁)。 这意味着,如果有多个线程同时访问同一个对象的这个同步方法,那么在同一时刻只能有一个线程执行该方法,其他线程必须等待锁被释放。 但是,如果多个线程访问的是不同对象的这个同步方法,那么它们可以并行执行,因为每个对象实例都有自己的锁。示例代码:
public class Counter { private int count = 0; public synchronized void increment() { count++; } }在这个例子中,
increment方法被synchronized修饰,它会对调用它的Counter对象实例加锁。 -
修饰静态方法: 当
synchronized修饰一个静态方法时,它实际上是对这个类的Class对象加锁。 因为静态方法是属于类的,而不是类的某个特定实例的,所以无论创建了多少个类的实例,调用静态同步方法时, 所有的实例都共享同一个锁(即类的Class对象锁)。 这意味着,如果有多个线程同时调用同一个类的这个静态同步方法,那么在同一时刻只能有一个线程执行该方法,其他线程必须等待锁被释放。示例代码:
public class StaticCounter { private static int count = 0; public static synchronized void increment() { count++; } }在这个例子中,
increment方法是静态的,并且被synchronized修饰,它会对StaticCounter类的Class对象加锁。
总结:
synchronized修饰非静态方法时,是对调用该方法的对象实例加锁。synchronized修饰静态方法时,是对这个类的Class对象加锁。
总结
| 修饰对象 | 锁对象 | 互斥情况 |
|---|---|---|
| 非静态方法 | 实例对象 | 同一实例的不同synchronized非静态方法间互斥,不同实例间不互斥 |
| 静态方法 | Class对象 | 同一类的不同synchronized静态方法间互斥,不同类间不互斥 |
注意事项
- 避免过度同步:过多的
synchronized可能会导致性能问题,因为它会限制并发执行的能力。应该只在确实需要保证数据一致性和线程安全的情况下使用synchronized。 - 锁的粒度:选择合适的锁粒度也很重要。锁粒度太大可能会导致性能问题,而锁粒度太小则可能无法有效保护共享数据。
- 锁的公平性:Java中的
synchronized锁并不是公平的,即等待时间最长的线程并不一定能先获得锁。如果需要公平的锁,可以考虑使用ReentrantLock等显式锁。
以上信息基于Java语言的特点和synchronized关键字的官方文档及广泛认可的实践经验。