如果一个类可能会和非信任代码交互,使用 private final lock object

共享可变变量的同步访问方法有2种:方法同步和代码块同步。方法被申明为synchronized,或者代码块使用this,他们都使用这个Object的内置锁作为监视器。攻击者能够非法长期获得并持有锁,导致Dos.

解决办法是使用 private final lock object. 它使用了对象this内部申明的field而不是this对象的内置锁。实现方法是 synchronized(obj)而不是 synchronized 方法,攻击者由于访问不到this内部private field,获取不到obj,所以没法造成锁竞争。

对于静态方法,static synchronized方法也容易被攻击。当静态方法被申明为synchronized,执行时会获得该class对象内置锁。非信任代码可以通过object.getClass()方法获得class对象的内置锁。
所以对于static field, 需要用private static final Object上锁来维护它

举几个例子加深理解


  1. 方法同步, 非信任代码获取object后无限期锁住它导致changeValue()获取不到锁
public class SomeObject {

    // Locks on the object's monitor
    public synchronized void changeValue() {
        // ...
    }
    
    public static SomeObject lookup(String name) {
        // ...
    }
}

// Untrusted code
String name = // ...
SomeObject someObject = SomeObject.lookup(name);
if (someObject == null) {
    // ... handle error
}
synchronized (someObject) {
    while (true) {
        // Indefinitely lock someObject
        Thread.sleep(0x7FFFFFFF);
    }
}
  1. Public Non-final Lock Object, 非信任代码可以修改lock指向,比如Integer.valueOf(1),利用IntegerCache搞成全局锁
public class SomeObject {
  public Object lock = new Object();
 
  public void changeValue() {
    synchronized (lock) {
      // ...
    }
  }
}
  1. Private Final Lock Object, 正确合规, lock私有且不可改变,多线程调用this.changeValue方法井然有序
public class SomeObject {
  private final Object lock = new Object(); // private final lock object
 
  public void changeValue() {
    synchronized (lock) { // Locks on the private Object
      // ...
    }
  }
}
  1. 静态不合规同步方法,非信任代码可以获取类型并无限期加锁,导致changeValue()获取不到锁
public class SomeObject {
  //changeValue locks on the class object's monitor
  public static synchronized void changeValue() {
    // ...
  }
}
 
// Untrusted code
synchronized (SomeObject.class) {
  while (true) {
    Thread.sleep(Integer.MAX_VALUE); // Indefinitely delay someObject
  }
}
  1. private static final Object, 正确合规 , SomeObject.lock静态私有且不可改变,多线程调用 SomeObject.changeValue方法井然有序
public class SomeObject {
  private static final Object lock = new Object();
 
  public static void changeValue() {
    synchronized (lock) { // Locks on the private Object
      // ...
    }
  }
}