程序清单3-7 展示了在构造函数中的隐式的使用this引用溢出
可能造成风险:
public class ThisEscape {
//新增一个age变量
private int age;
//注意:一般此时构造函数是public,任何可以访问
public ThisEscape(EventSource source) {
source.registerListener(new EventListener({
public void onEvent(Event e){
doSomething(e);
}
} )
);
//[ref1]如果代码运行至此处,另外一个线程触发doSomething方法
age= 18;
}
public void doSomething(Event e) {
if (age < 18) {
drinkWater();
}
if (age > 18) {
drinkWine();
}
}
}
那么,在构造过程中使用this引用溢出的错误是,在构造函数中启动一个线程,this引用都会被新创建的线程共享。在对象尚未完全构造之前,新的线程就可以看见它。
我们假设不创建这个线程,但是外部已经存在一个线程,比如上面的例子中,如果代码执行到[ref1]处某个外部线程事件触发doSomething(),由于age未赋值18,导致结果与预期不一致。
程序清单3-8 使用工厂方法来防止this引用在构造函数中溢出
什么是工厂方法?就是目标是私有的,仅暴露public的方法给你间接用,你自身无法直接去访问该私有目标。
public class SafeListener {
private final EventListener listener;
private int age;
// 私有的构造函数
private SafeListener(){
listener = new EventListener({
public void onEvent(Event e){
doSomething(e);
}
} ) ;
//赋值
age= 18;
}
public void doSomething(Event e) {
if (age < 18) {
drinkWater();
}
if (age > 18) {
drinkWine();
}
}
//public的工厂方法
public static SafeListener newInstance(EventSource source) {
//调用构造函数
SafeListener safe = new SafeListener();
//在注册之前,构造函数已经完全构造成功了,age已经完成赋值操作
source.registerListener(safe.listener);
}
}