发布(Publish)一个对象是指使对象能够在当前作用域之外的代码中被使用。例如将指向该对象的引用保存到其他代码可以访问到的地方 ,或者在一个非私有的方法中返回一个对象的引用或者将该引用传递到其他类的方法中。当发布一个对象时,在该对象的非私有域中的引用同样被发布出去,一般来说如果一个已经发布的对象能够通过非私有的变量和方法调用到其他的对象那么这个对象也被发布。
逸出(Escape)是指 一个比应该被发布的对象被发布出去。
在 《Java Concurrency in Practice》中关于隐式使用This 引用逸出的示例,比较难以理解如何逸出。ThisEscape发布EventListener时,也隐含地发布了ThisEscape实例本身,因为在这个内部类的实例中包含了对ThisEscape 实例的隐含引用。这个个人的理解代码是:
/** * * @author zhangwei_david * @version $Id: ThisEscape.java, v 0.1 2014年11月3日 上午9:37:54 zhangwei_david Exp $ */ public class ThisEscape { private String name = null; public ThisEscape(EventSource source) { source.registerListener(new EventListener() { public void onEvent(Event event) { doSomething(event); } }); name = "TEST"; } /** * * @param event */ protected void doSomething(Event event) { System.out.println(name.toString()); } } import java.awt.Event; /** * * @author zhangwei_david * @version $Id: Listener.java, v 0.1 2014年11月3日 上午9:40:13 zhangwei_david Exp $ */ public interface EventListener { public void onEvent(Event event); }
/** * * @author zhangwei_david * @version $Id: EventSource.java, v 0.1 2014年11月3日 上午9:38:40 zhangwei_david Exp $ */ public class EventSource { public void registerListener(EventListener listener) { listener.onEvent(null); } }
/** * * @author zhangwei_david * @version $Id: Client.java, v 0.1 2014年11月3日 上午9:45:48 zhangwei_david Exp $ */ public class Client { /** * * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { EventSource es = new EventSource(); new ThisEscape(es); } }
运行的结果是:
Exception in thread "main" java.lang.NullPointerException at com.cathy.demo.concurrency.escape.ThisEscape.doSomething(ThisEscape.java:33) at com.cathy.demo.concurrency.escape.ThisEscape$1.onEvent(ThisEscape.java:21) at com.cathy.demo.concurrency.escape.EventSource.registerListener(EventSource.java:15) at com.cathy.demo.concurrency.escape.ThisEscape.<init>(ThisEscape.java:18) at com.cathy.demo.concurrency.escape.Client.main(Client.java:21)
这个就是由于在name 初始化之前,就使用了ThisEscape实例,而此时实例尚未完成初始化。
同样修改SafeListener
import java.awt.Event; /** * * @author zhangwei_david * @version $Id: SafeListener.java, v 0.1 2014年11月3日 上午10:20:26 zhangwei_david Exp $ */ public class SafeListener { private final EventListener listener; private String name = null; private SafeListener() { listener = new EventListener() { public void onEvent(Event event) { doSomething(); } }; name = "TEST"; } public static SafeListener newInstance(EventSource eventSource) { SafeListener safeListener = new SafeListener(); eventSource.registerListener(safeListener.listener); return safeListener; } /** * */ protected void doSomething() { System.out.println(name.toString()); } } /** * * @author zhangwei_david * @version $Id: Client.java, v 0.1 2014年11月3日 上午9:45:48 zhangwei_david Exp $ */ public class Client { /** * * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { EventSource es = new EventSource(); // new ThisEscape(es); SafeListener.newInstance(es); } }
结果是:
TEST