现代编程离不开并发,但并发效率提升的同时也带来了一些问题,比如程序奇怪的执行顺序,诡异的行为,Java 为了解决这个问题提出了一套内存模型 (JMM),同时我们需要注意的是,我们真正要了解的是什么,是 Java语言规范关于 JMM 定义的规则,还是 JVM 对于 JMM 的的具体实现,本文主要根据 JSR 133 讨论 Java 语言规范 关于 JMM 定义的规则

顺序一致模型

顺序一致性是程序执行过程中可见性和顺序的强有力保证。在顺序一致的执行过程 中,所有动作(如读和写)间存在一个全序关系,与程序的顺序一致。

通俗的讲保证程序执行的顺序与代码的顺序一致(不会由于编译器的优化而发生重排序),但其并不意味着并发安全。

每个动作都是原子的且立即对所有线程可见。如果一个程序没有数据争用,那么该 程序的执行看起来将是顺序一致的。如前面所提到的,在一组操作要保持原子性而 未得到保证时,即使有顺序一致性 和/或 未遭遇数据争用(当程序包含两个没有被 happens-before 关系排序的冲突访问时,就称存在数据争 用),仍然可能会出现错误。

  • 假想一个情况使用 volatile 修饰的变量在多线程的进行 10000 次自增操作,不会发生重排序,满足上述的顺序一致性和没有数据争用。但由于自增操作不是原子的 取值,加一,写回。在取值和加一的间隙其它线程进行 自己的自增操作,造成结果错误。

显而易见的可以知道JMM不会也不能选择顺序一致模型,因为其禁止了编译优化,造成性能上的影响。

Happens-before 模型

happens-before 内存模型描绘了一个必要而非充分的约束集。所有 Java 内存模型允 许的行为,happens-before 内存模型也允许,但是,happens-before 内存模型允许不 可接受的行为 —— 这些行为违反了我们建立的需求

规则

  1. 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;
  2. 锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作;
  3. volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作;
  4. 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;
  5. 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;
  6. 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;
  7. 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;
  8. 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始;
    这些规则和同步相结合保证了前一个动作对后一个动作的可视性。

太弱了

但是 Happens-before 的一致性允许一个对变量V读操作看到之前的写操作。。

  • 这种比较弱的模型有一个致命的缺点,其允许值“凭空出现”.
x==y==0;
//Thread 1
r1 = x;
if (r1 != 0)
y = 1;
// Thread 2
r2 = y;
if (r2 != 0)
x = 1;

其中 r1 == r2 == 0 是JMM允许的唯一的合法行为。
然而,在 happens-before 内存模型下,存在执行结果是 r1 == r2 == 1 的情 况,允许每个读操作看到其它线程写的值(重排序带来的写操作提前执行)。

x==y==0;
//Thread 1
r1 = x;
y = r1;
// Thread 2
r2 = y;
x = r2;

会发生循环依赖,激进的编译器可能会随意赋值 r1 == r2 == 42 .同样是不被允许的。

因果关系

当一个写操作发生在了一个其依赖的读操作之前,我们将这样的问题称为因果关系,因为它涉及写操作是否会触发自身发生的问题。

从上文可以看到 Happens-before 并不能很好的处理这些问题,JMM借助因果关系处理这些问题。

  • Java 内存模型将一个特定的执行过程和一个程序作为输入,然后确定该执行过程是 否是该程序的一次合法执行。它是通过逐步地建立一组“提交的”动作来实现的,这 些动作反映出了我们知道的哪些动作能够被程序执行而不需要一个“因果循环”。
    当然JMM允许编译器通过一些正确的优化打破一些 ”因果循环“。为了保证不要出现因果循环可以禁止相关指令的重排。

可以看到的是 volatile 的实现保证了可见性又禁止了相关指令的重排

JSR 133
JSR Review

posted on 2025-03-12 15:05  嗯嗯好傅  阅读(16)  评论(0)    收藏  举报