Java基础六:synchronized

78 阅读3分钟

在Java中,synchronized关键字是一个非常重要的同步机制,它可以用来修饰方法或代码块,以确保在同一时刻最多只有一个线程可以执行某个方法或代码块。synchronized修饰静态方法和非静态方法时,其作用范围和行为是有所不同的。

  1. 修饰非静态方法: 当synchronized修饰一个非静态方法时,它实际上是对调用该方法的对象实例加锁(也称为对象锁或实例锁)。 这意味着,如果有多个线程同时访问同一个对象的这个同步方法,那么在同一时刻只能有一个线程执行该方法,其他线程必须等待锁被释放。 但是,如果多个线程访问的是不同对象的这个同步方法,那么它们可以并行执行,因为每个对象实例都有自己的锁。

    示例代码:

    public class Counter {
        private int count = 0;
    
        public synchronized void increment() {
            count++;
        }
    }
    

    在这个例子中,increment方法被synchronized修饰,它会对调用它的Counter对象实例加锁。

  2. 修饰静态方法: 当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静态方法间互斥,不同类间不互斥

注意事项

  1. 避免过度同步:过多的synchronized可能会导致性能问题,因为它会限制并发执行的能力。应该只在确实需要保证数据一致性和线程安全的情况下使用synchronized
  2. 锁的粒度:选择合适的锁粒度也很重要。锁粒度太大可能会导致性能问题,而锁粒度太小则可能无法有效保护共享数据。
  3. 锁的公平性:Java中的synchronized锁并不是公平的,即等待时间最长的线程并不一定能先获得锁。如果需要公平的锁,可以考虑使用ReentrantLock等显式锁。

以上信息基于Java语言的特点和synchronized关键字的官方文档及广泛认可的实践经验。