Java内存模型:Java如何解决有序性和可见性

想要写好一个高可用的并发程序,对Java内存模型理解是必不可少的。在Java并发编程中,导致可见性的原因是缓存导致有序性的原因是编译器优化。如果通过禁用缓存和编译器优化来保证并发的安全性,那么程序应该会慢的跟蜗牛一样。所以,合理的方案是按需禁用缓存以及编译优化。Java是通过Java内存模型实现这个功能的。具体来说是通过 volatile、synchronized、final三个关键字以及happens-before规则来实现的。

  • 锁操作具备happens-before关系,解锁操作happens-before之后对同一把锁加锁的操作。实际上,在解锁的过程中,JVM需要强制刷新缓存,使得当前线程所做的修改可以对其他线程可见。

  • volatile字段:volatile可以看成是一种不保证原子性但保证可见性的特性,性能优于锁。

  • final修饰符:final修饰的实例字段则是涉及到新建对象的发布问题,当一个对象包含final修饰的实例字段时,其他线程能够看见已经初始化的final实例字段,这是安全的。

Happens-before规则

关于Happens-before规则的理解
错误理解:前面的一个操作发生在后续操作的前面
正确理解:前面一个操作的结果对后续操作是可见的

  1. 程序次序规则:在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作,准确的说,应该是控制流顺序(包含分支)。

  2. 管程锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作。

  3. volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作。

  4. 线程启动规则:Thread对象的start()方法先行发生于此线程的没一个动作。

  5. 线程终止规则:线程中的所有操作都先行发生于对此线程的终止规则。

  6. 线程中断规则:对线程interrupt()的调用先行发生于被中断线程的代码检测到中断事件的发生。

  7. 对象终结规则:一个对象的初始化完成先行发生于它的finalize()方法的开始

Java内存模型主要是通过内存屏障禁止重排序的。对于编译器而言,内存屏障限制它所能做的重排序优化。对于处理器而言,内存屏障将会导致缓存的刷新操作。

说点什么

avatar
  Subscribe  
提醒

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部