JAVA Concurrency - SafePoint中的私有构造方法解释

卓二妹原创,转载请注明来源。

@ThreadSafe
public class SafePoint {
    @GuardedBy("this") private int x, y;
    private SafePoint(int[] a) { this(a[0], a[1]); }
    public SafePoint(SafePoint p) { this(p.get()); }
    public SafePoint(int x, int y) {
        this.x = x;
        this.y = y; 
    }
    public synchronized int[] get() {
        return new int[] { x, y };
    }
    public synchronized void set(int x, int y) {
        this.x = x;
        this.y = y; 
    }
}

 java并发编程中对这段代码有一段让人比较费解的描述:

写道
The private constructor exists to avoid the race condition that would occur if the copy constructor were implemented as this(p.x, p.y); this is an example of the private constructor capture idiom (Bloch and Gafter, 2005).

 

这里如果将private SafePoint(int[] a) { this(a[0], a[1]); }方法改为public就会有race condition问题。为什么呢?

因为如果我们要复制一个SafePoint对象时,我们会首先想到编写下面这样一个方法:

 public SafePoint(SafePoint safePoint){
     this(safePoint.x, safePoint.y);
 }

但是当我们在通过复制originalSafePoint创建新的SafePoint对象时,可能有一个线程正在调用originalSafePoint.setXY方法,导致读取safePoint.x, safePoint.y这对值可能一个更新了而一个没更新,出现线程不安全。因此x,y必须同时读取出来。所以在复制的时候,不能像上面那样调用,而要用getXY()把x y一起取出来。

 public SafePoint(SafePoint safePoint){
     int [] xy = safePoint.getXY();
     this(xy[0], xy[1]);
 }

 上面的代码会有编译错误,因为this()必须是body的第一行:


 

那么好吧,那我们这样写就行了是吗?

    public SafePoint(SafePoint originalSafePoint){
        this(originalSafePoint.getXY()[0],originalSafePoint.getXY()[1]);
    }

显然这样也是有问题的,因为originalSafePoint.getXY()被调用了两次,这时候两次取出来的x y已经不是一对值了。

因此我们只有提供一个构造方法接受getXY()返回的数组作为参数,来复制一个对象:

public SafePoint(SafePoint originalSafePoint){
    this(originalSafePoint.getXY());
}
private SafePoint(int [] xy){
    this(xy[0], xy[1]);
}

这样就避免了上面的copy constructor的问题。现在再来读一下作者说的这句话就清楚很多了:

写道
The private constructor exists to avoid the race condition that would occur if the copy constructor were implemented as this(p.x, p.y);

 私有的构造方法的存在,是为了避免在复制构造函数(即SafePoint(SafePoint originalSafePoint))的中因调用this(p.x, p.y)而引起的race condition。

猜你喜欢

转载自zhuoyaopingzi.iteye.com/blog/2398892