JMM的思考

1.多线程本身固有的问题

  • 1)竞争问题,例如两个线程同时对同一个内存位置的操作
  • 2)顺序问题
    比如生产者当队列满时需要等待,消费者当队列为空时需要等待;
    比如一个线程需要读取另外一个线程设置的值(或者初始化的值)

2.现代计算机系统引入的额外复杂度

  • 1)指令重排
    在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序。
  • 2)缓存系统
    对变量的修改还在当前CPU的缓存中,没有刷新到主存,对其他线程不可见。

指令重排和缓存系统都会较大概率产生顺序问题,尤其是涉及到初始化问题。一个线程没有初始化好,另外一个线程就使用。


JMM的思考_第1张图片

3.怎样解决这些问题

  • 1)初步要求——as-if-serial (重排序)
    不管如何重排序,都必须保证代码在单线程下的运行正确。
    编译器和处理器不会对存在数据依赖关系的操作做重排序,因为这种重排序会改变执行结果。
    在单线程程序中,对存在控制依赖的操作重排序,不会改变执行结果(这也是as-if-serial语义允许对存在控制依赖的操作做重排序的原因);但在多线程程序中,对存在控制依赖的操作重排序,可能会改变程序的执行结果。

  • 2)程序执行时的语义不能被改变(即执行结果不能被改变)—— Happens-Before (重排序)
    用happens-before的概念来阐述操作之间的内存可见性。
    程序顺序规则;monitor锁;volatile;传递性;start;join;中断规则

  • 3)内存屏障——禁止特定类型的处理器重排序

  • 4)临界区——处理竞争问题

4.总结

从上面的讨论可知,所有的这些措施都只不过是解决多线程并发的两个问题——竞争问题和顺序问题。

  • 1)竞争问题可以通过临界区来解决,即锁
  • 2)顺序问题 在指令重排序 和 缓存系统 的影响下显得更为突出,Java通过as-if-serial规则保证单线程下执行的正确性,通过Happens-Before保证操作之间的可见性,通过内存屏障禁止掉可能带来顺序问题的重排序。

你可能感兴趣的:(JMM的思考)