安全发布对象——发布与逸出

对象发布

使一个对象能够被其他范围之外的对象/代码所使用。

实际日常开发中经常发布对象的例子有:

  1. 通过类的非私有方法,返回对象的引用;
  2. 通过公有的静态变量发布对象

对象逸出

是一种错误的对象发布。当一个对象还未构造完成就已经被其他的线程观察到。

发布对象示范例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Slf4j
@NotThreadSafe
public class NotSafePublish {

private String[] states = {"a", "b", "c"};

//通过类的非私有方法,返回对象的引用
public String[] getStates() {
return states;
}

public static void main(String[] args) {
NotSafePublish unsafePublish = new NotSafePublish();
log.info("{}", Arrays.toString(unsafePublish.getStates()));

//通过上面的非法发布,修改其私有变量
unsafePublish.getStates()[0] = "d";
log.info("{}", Arrays.toString(unsafePublish.getStates()));
}
}

观察结果:

图示

显然该发布方式是非线程安全的。

对象逸出示范例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Escape {

//定义可能会逸出的私有变量
private int thisCanEscape = 0;

//返回一内部类的引用
public Escape () {
new InnerClass();
}

//私有内部类
private class InnerClass {
public InnerClass() {
log.info("{}", Escape.this.thisCanEscape);
}
}

public static void main(String[] args) {
//调用公有方法
new Escape();
}
}

观察结果:

图示

显然内部类的成员变量被一个公有方法观察到了!

小结

显然上述的方式都是错误的,不被推荐的!
不正确地发布对象可能会导致两种错误:

  1. 发布对象所在线程以外的线程都可以看到发布对象的值(状态)。
  2. (更严重)其他线程看到的对象的引用是最新的,但值(状态)是已过期的。

若该对象是可变对象,那么它必须要被安全发布。 对象未完成之前不可以将其发布。 多多注意。

避免方法:通过专有的start()或初始化方法统一启动。其中可以采用工厂方法结合私有构造函数,完成对象的创建和监听器的注册

SupriseMF wechat
欢迎关注微信订阅号【星球码】,分享学习编程奇淫巧技~
喜欢就支持我呀(*^∇^*)~

热评文章