私有构造函数捕获模式

私有构造函数捕获模式

最近看《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).

结合原文代码:

@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;
    }
}

这里的构造器public SafePoint(SafePoint p) { this (p.get()); }是为了捕获另一个实例的状态。get()方法是一个同步方法,为了避免竞态没有分别提供x、y的公有getter方法。

为了保证SafePoint的多线程安全性,在使用另一个实例构造新的实例时,使用了一个私有的构造器。

首先为什么不用下面这种,还是为了避免竞态(p.x和p.y调用不是原子操作)。

public SafePoint(SafePoint p) {
	this(p.x, p.y)
}

同理,这种也不行,两次调用get()方法不是原子操作。

public SafePoint(SafePoint p) {
	this(p.get()[0], p.get()[1])
}

为什么不用直接用数组,编译不通过:Call to “this()” must be first statement in constructor body

public SafePoint(SafePoint p) {
 	int[] a = p.get();
	this(a[0], a[1]);
}

为什么接受数组为参数的构造器不能公开,数组a是有外部传入的,并不能保证数组内容不会其他线程修改或者传入的数组是非法的(例如长度并不为2,这里只允许接收两个单位长度的数组分别作为x和y)。

public SafePoint (int [] a) {
	this (a[0], a[1]); 
}

当然我们可以使用下面这种代替私有的构造器,这种方法是安全的,但是会产生重复的初始化代码。

public SafePoint(SafePoint p) {
    int[] a = p.get();
    this.x = a[0];
    this.y = a[1];
}

再回头看SafePoint的线程安全性,SafePoint有两个状态变量x、y。为了保证线程安全性,没有为其分别提供getter和setter方法,而是将其封装后发布并使用内置锁保护。

可以参考stackoverflow上的示例代码。
原文链接(学到了东西就点个赞吧!!!)

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值