发布(Publish):发布一个对象的意思是指,使对象能够在当前作用域之外的代码中使用。例如:
逸出:当某个不应该发布的对象被发布时,这种情况就被称为逸出。
1、发布一个对象最简单的方法是将对象的引用保存在一个公有的静态变量中,以便任何类和线程都能看到该对象。
public static Set<Secret> knownSecrets;
public void initialize(){
knownSecrets = new HashSet<Secret>();
}
当发布一个对象时,可能会间接的发布其他对象。例如上面的代码,如果向集合knownSecrets中添加一个Secret对象,那么该对象也会发布,因为任何代码都可以遍历这个集合,并获得对这个Secret对象的引用。
2、同样,如果从非私有方法中返回一个引用,那么同样会发布返回的对象。
class UnsafeStates{
private String[] states = new String[]{
"A","B","C"
};
public String[] getStates(){ return states; }
}
当发布一个对象时,在该对象的非私有域中引用的所有对象都将会被发布。一般来说,如果一个已经发布的对象能够通过非私有的变量引用和方法调用到达其他的对象,那么这些对象也都会被发布。
“外部方法”:指行为上并不完全由本类来规定的方法,包括其他类中定义的方法以及本类中可以被改写的方法(既不是私有方法也不是终止[final]方法)。当把一个对象传递给外部方法时,就相当于发布了该对象。
3、发布一个内部类的实例。如下代码,当ThisEscape发布EventLinstener时,也隐含发布了自己本身。因为内部类默认持有外部类的一个引用。
public class ThisEscape{
public ThisEscape(EventSource source){
source.registerListener(
new EventListener(){
public void onEvent(Event e){
doSomething(e);
}
});
}
}
在上述代码中,ThisEscape中给出了一个特殊示例,即this引用在构造函数中逸出。
当且仅当对象的构造函数返回时,对象才处于可预测的、一致的状态。因此,当从对象的构造函数中发布对象时,只是发布了一个尚未完成构造的对象。即使发布对象语句放在构造函数的最后一行也是如此。如果this引用在构造函数中逸出,则这种对象被认为是不正确的构造。
安全发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见。一个正确构造的对象可以通过以下方式安全地发布:
通常,要发布一个静态构造对象,最简单最安全的方式是使用静态的初始化器:
public static Holder holder = new Holder(42);
静态初始化构造器由JVM在类的初始化阶段执行。由于JVM内部存在同步机制,因此通过这种方式初始化的任何对象可以被安全地发布。