发布与逸出

发布(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引用在构造函数中逸出,则这种对象被认为是不正确的构造。

安全发布:

  • 不可变对象:满足不可变性的所有要求:状态不可修改、所有域都是final、正确的构造过程。
  • 事实不可变对象:对象从技术上看是可变的,但其状态在发布后不会再改变。
  • 可变对象:对象在构造后可以修改。
  1. 任何线程都可以在不需要额外同步的情况下安全地访问不可变对象,即使在发布这些对象时没有同步。
  2. 在没有额外同步的情况下,任何线程都可以安全地使用被安全发布的事实不可变对象。
  3. 可变对象必须通过安全方式来发布,并且必须是线程安全的或由某个锁保护起来。

安全发布的常用模式:

安全发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见。一个正确构造的对象可以通过以下方式安全地发布:

  • 在静态初始化函数中初始化一个对象引用。
  • 将对象的引用保存到volatile类型的域中或AtomicReferance对象中。
  • 将对象的引用保存在某个正确构造对象的final类型域中。
  • 将对象的引用保存到一个由锁保护的域中。

通常,要发布一个静态构造对象,最简单最安全的方式是使用静态的初始化器:

public static Holder holder = new Holder(42);

静态初始化构造器由JVM在类的初始化阶段执行。由于JVM内部存在同步机制,因此通过这种方式初始化的任何对象可以被安全地发布。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android Note

Kotlin —  Destructuring Declarations(解构声明)

14220
来自专栏我是攻城师

在Scala里面如何使用元组

37840
来自专栏从流域到海域

《笨办法学Python》 第11课手记

《笨办法学Python》 第11课手记 本节课讲了一个用来输入的函数raw_input,而我们一直用的print其实是一个用来输出的函数。 原代码如下: pri...

24990
来自专栏Linyb极客之路

并发编程之Synchronized关键字

一、Synchronized的基本使用 Synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法。Synchronized的作...

30460
来自专栏小二的折腾日记

面试总结-C++

堆、栈、自由存储区、全局/静态存储区、常量存储区 自由存储区存储malloc申请的内存 (1)从静态存储区域分配 。内存在程序编译的时候就已经分配好,这块内存在...

24010
来自专栏魂祭心

原 Curry的js实现

36750
来自专栏大眼瞪小眼

PHP HashTable总结

本篇文章主要是对 PHP HashTable 总结,下面的参考链接是很好的学习资料。学习“散列”这个数据结构—推荐《数据结构与算法分析 C语言描述》

17610
来自专栏java学习

Java基础总结大全(1)

一、基础知识: 1、JVM、JRE和JDK的区别: JVM(Java Virtual Machine):java虚拟机,用于保证java的跨平台的特性。 ...

451110
来自专栏郑科的专栏

PHP7 新特性简介(一)

PHP7是PHP编程语言全新的一个版本,在性能方面获得了极大的提升。官方的文档显示,PHP7可以达到PHP5.x版本两倍的性能。同时还提供了很多其他语言流行的语...

69000
来自专栏大闲人柴毛毛

三分钟理解“模板方法模式”——设计模式轻松掌握

模板方法模式的官方定义: 在模板方法模式中,只定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定...

375100

扫码关注云+社区

领取腾讯云代金券