为什么同步块比同步方法更好?

2022-08-31 10:25:35

我已经开始在线程中学习同步。

同步方法:

public class Counter {

   private static int count = 0;

   public static synchronized int getCount() {
      return count;
   }

   public synchronized setCount(int count) {
      this.count = count;
   }

}

同步块:

public class Singleton {

   private static volatile Singleton _instance;

   public static Singleton getInstance() {
      if (_instance == null) {
         synchronized(Singleton.class) {
            if (_instance == null)
               _instance = new Singleton();
         }
      }
      return _instance;
   }
}

我应该何时使用方法和阻止?synchronizedsynchronized

为什么块比方法好?synchronizedsynchronized


答案 1

这不是一个更好的问题,只是不同。

同步方法时,可以有效地同步到对象本身。对于静态方法,您将同步到对象的类。因此,以下两段代码以相同的方式执行:

public synchronized int getCount() {
    // ...
}

这就像你写的一样。

public int getCount() {
    synchronized (this) {
        // ...
    }
}

如果要控制与特定对象的同步,或者只想将方法的一部分同步到该对象,请指定一个块。如果在方法声明中使用关键字,它将整个方法同步到对象或类。synchronizedsynchronized


答案 2

尽管通常不是问题,但从安全角度来看,最好在私有对象上使用synced,而不是将其放在方法上。

将其放在方法上意味着您正在使用对象本身的锁来提供线程安全性。使用这种机制,代码的恶意用户也可以获得对象上的锁定,并永久保留它,从而有效地阻止其他线程。非恶意用户可能会无意中有效地执行相同的操作。

如果使用私有数据成员的锁,则可以防止这种情况,因为恶意用户不可能获取私有对象上的锁。

private final Object lockObject = new Object();

public void getCount() {
    synchronized( lockObject ) {
        ...
    }
}

这种技术在布洛赫的《有效的Java》(第2版)第70项中有所提及。