定义: 是一个对象可以被当前范围以外的代码所使用
一种错误的发布。当一个对象该没有构造完成时,就使被其余线程所见。
下面咱们来看一下没有安全发布的对象java
@Slf4j public class UnsafePublish { private String[] states = {"a", "b", "c"}; public String[] getStates() { return states; } public static void main(String[] args) { UnsafePublish unsafePublish = new UnsafePublish(); log.info("{}", Arrays.toString(unsafePublish.getStates())); unsafePublish.getStates()[0] = "d"; log.info("{}", Arrays.toString(unsafePublish.getStates())); } }
咱们看这段代码,咱们建立了一个对象经过getStates方法咱们能够获取这个对象的数组,此时咱们将数组内容打印出来结果,若是此时咱们将这个对象发布出去,而后其余线程(这里没有模拟其余线程对其修改)又对这个对象的states的值进行修改,此时在拿到这个对象的指望的是没有被修改的,事实上获得的对象是修改事后的。也就是说咱们不能直接经过一个public的一个set方法就行return。数组
下面咱们再看一段对象溢出的代码安全
public class ThisEscape { public ThisEscape(EventSource source) { source.registerListener(new EventListener() { public void onEvent(Event e) { doSomething(e); } }); } void doSomething(Event e) { } interface EventSource { void registerListener(EventListener e); } interface EventListener { void onEvent(Event e); } interface Event { } }
这将致使this逸出,所谓逸出,就是在不应发布的时候发布了一个引用。在这个例子里面,当咱们实例化ThisEscape对象时,会调用source的registerListener方法,这时便启动了一个线程,并且这个线程持有了ThisEscape对象(调用了对象的doSomething方法),但此时ThisEscape对象却没有实例化完成(尚未返回一个引用),因此咱们说,此时形成了一个this引用逸出,即尚未完成的实例化ThisEscape对象的动做,却已经暴露了对象的引用。其余线程访问尚未构造好的对象,可能会形成意料不到的问题。函数
public class SafeListener { private final EventListener listener; private SafeListener() { listener = new EventListener() { public void onEvent(Event e) { doSomething(e); } }; } public static SafeListener newInstance(EventSource source) { SafeListener safe = new SafeListener(); source.registerListener(safe.listener); return safe; } void doSomething(Event e) { } interface EventSource { void registerListener(EventListener e); } interface EventListener { void onEvent(Event e); } interface Event { } }
在这个例子中咱们使用匿名类的形式来构造,只有在整个对象都实例化好了才能会执行。只有当构造函数返回时,this引用才应该从线程中逸出。构造函数能够将this引用保存到某个地方,只要其余线程不会在构造函数完成以前使用它this