Java并发编程2:对象的共享


作者: 康凯森

日期: 2016-11-19

分类: Java


本文将介绍如何共享和发布对象,从而使它们能够安全地由多个线程同时访问。

1 可见性

为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制

加锁的含义不仅有互斥行为,还包括内存可见性。

2 “重排序”

在没有同步的情况下,编译器处理器运行时等都可能对操作的执行顺序进行一些意想不到的调整。在缺乏足够同步的多线程程序中,要想对内存操作的执行顺序进行判断,几乎无法得到正确的结论。

3 非原子的64位操作

在多线程程序中使用共享且可变long和double等类型的变量也是不安全的,除非用关键字volatile来声明它们,或者用锁保护起来。

4 Volatile变量

volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。

volatile变量只能确保内存可见性。

volatile变量的一种典型用法:检查某个状态标记以判断是否退出循环

5 对象的发布与逸出

对象的发布:使对象能够在当前作用域之外的代码中使用。

对象的逸出:某个不应该发布的对象被发布。

当发布一个对象时,在该对象的非私有域中引用的所有对象同样会被发布。

/**
 * bad case: 使内部的可变状态逸出
 * Created by kangkaisen on 2016/11/19.
 */
public class UnsafeStates {
    private String[] states = new String[] { "KKS", "test" };

    public String[] getStates() {
        return states;
    }
}
/**
 * bad case: 隐式地使this引用逸出
 * Created by kangkaisen on 2016/11/19.
 */
public class ThisEscape {
    public ThisEscape(EventSource source) {
        source.addErrorListener(
                new EventListener() {
                    public void onEvent(Event e) {
                        doSomething(e);
                    }
                }
        );
    }
}

如果需要在构造函数中注册一个事件监听器或启动线程,那么可以使用一个私有的构造函数和一个公共的工厂方法。

6 线程封闭

线程封闭:仅在单线程内访问数据。

  • 栈封闭:只能通过局部变量才能访问对象。
  • ThreadLocal

7 不变性

不可变对象:一个对象在创建后其状态就不能被修改,则称此对象是不可变对象。

不可变对象一定是线程安全的。

不可变对象需要满足的条件:

  • 对象创建以后其状态就不可改变
  • 对象的所有域都是final类型
  • 对象是正确创建的(在对象的创建期间,this引用没有逸出)

final域能够确保初始化过程中的安全性,从而可以不受限制地访问不可变对象,并在共享这些对象时无须同步。

除非某个域是可变的,否则应将其声明为final域

每当需要对一组相关数据以原子方式执行某个操作时,就可以考虑创建一个不可变类来包含这些数据。也就是说,对于在访问和更新多个相关变量时出现的竞争条件问题,可以通过将这些变量全部保存在一个不可变对象中来消除。

8 安全发布

一个正确构造的对象可以通过以下方式来安全地发布:

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

9 总结

对象的发布需求取决于它的可变性:

  • 不可变对象可以通过任意机制来发布
  • 事实不可变对象(技术上是可变的,但是状态在发布后不再改变。例如Date对象)必须通过安全方式来发布
  • 可变对象必须通过安全方式来发布,并且必须是线程安全的或者是由某个锁保护起来

在并发程序中使用和共享对象时,可以使用的一些实用策略:

  • 线程封闭
  • 只读共享:不可变对象和事实不可变对象。
  • 线程安全共享
  • 保护对象 :被保护的对象只能通过持有特定的锁来访问。

10 参考资料

本文是《Java 并发编程实战》的读书笔记。


《OLAP 性能优化指南》欢迎 Star&共建

《OLAP 性能优化指南》

欢迎关注微信公众号