上一篇文章我们说了,为了多线程并发场景下的对象安全共享, 线程封闭是你第三个可以遵守的原则,它包括了1)栈限制,2)ThreadLocal
今天编哥给大家说说最后俩事:不可变性和安全发布
不可变性
不可变就是最安全的一种对象,因为不存在任何线程能去写入新状态这件事,String 就是一个这样的不可变对象
它的特性如下:
- 创建后,其状态再也不能被改变,因为对象不向外暴露任何修改状态的方法;
- 他的所有 属性 都是 final 的(String这个类甚至都是final的,不允许扩展修改它)
- 构造期间,他的this引用没有逃逸出去;
安全发布
最后说一下共享你的对象的最后一步:安全发布
简单来说,就是我们不允许发布一个部分被初始化的对象。
public class Holder {
private int n;
public Holder(int n ){this.n = n}
public void assertSanity () {
if (n!=n) {
System.out.println("如果你看到这行字,那么这个对象是一个部分被初始化的对象,还不能用");
}
}
}
class Initer {
public Holder holder;
public void init() {
holder = new Holder(42);
}
}
class Test {
public void test() {
Initer.holder.assertSanity(); // 很可能 测试 看到了那行字
}
}
本来稍微等一会,这对象就准备好了(Initer完全走完 init()方法),但是就是时间早了一会,让客户程序(Test.test())看到一个 部分被初始化的对象,这种情况令一个本来还不错的对象变坏了
上面提到的不可变的对象,你怎么发布都是安全的
而其他类型的,大多数对象,发布的时候,都要注意安全问题,也就是你需要用锁保护,或者其他提到过的线程安全手段,比如封闭
总结
并发安全需要考虑很多,从根上考虑就是我们得创建一个安全用于共享的对象
回顾一下,为了安全共享你的对象,我们考虑4点:
- 可见性
- 发布和逸出的风险
- 线程封闭
- 不可变性 和 安全发布
如果你想看过往的文章,那么在这里:
https://blog.csdn.net/bianbrother/article/details/129339124
https://blog.csdn.net/bianbrother/article/details/129339287
https://blog.csdn.net/bianbrother/article/details/129339398