【多线程学习十三】有序性--指令重排及其优化

本文探讨了Java中的指令重排现象,这是JVM为了提高性能而进行的一种优化策略。在单线程环境下,指令重排不会影响结果,但在多线程中可能导致数据一致性问题。通过例子展示了volatile关键字如何防止指令重排,从而确保可见性和有序性。文章还提到了处理器的流水线技术,并提供了一个JCStress测试用例来展示并发情况下的指令重排问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有序性

jvm在不影响正确性的前提下,可以调整语句的执行顺序–》【指令重排】

多线程下【指令重排】会影响正确性,指令重排是JIT编译器在运行时的一些优化,该现象需要大量测试才能复现

static int i;
static int j;

// 在某个线程内执行如下赋值操作
i = ...; 
j = ...;

至于是先执行 i 还是 先执行 j ,对最终的结果不会产生影响。所以,上面代码真正执行时,既可以是

i = ...; 
j = ...;

也可以是

j = ...;
i = ...;

指令重排优化

事实上,现代处理器会设计为一个时钟周期完成一条执行时间最长的CPU指令,指令还可以再划分为一个个更小的阶段,例如把每条指令划分为:取指令——指令译码——执行指令——内存访问——数据写回

在这里插入图片描述

在不改变程序结果的前提下,这些指令的各个阶段可以通过重排序组合来实现指令级并行

指令重排的前提是重排指令不能影响结果

// 可以重排的例子
int a = 10; // 指令1
int b = 20; // 指令2
System.out.println( a + b );

// 不能重排的例子
int a = 10; // 指令1
int b = a - 5; // 指令2

支持流水线的处理器
cpu可以在一个时钟周期内同时运行多条指令的不同阶段(其实相当于一条执行时间最长的复杂指令),本质上流水线技术并不能缩短单条指令的执行时间,但是变相提高了指令的吞吐率
在这里插入图片描述

解决指令重排问题

volatile修饰的变量可以禁用指令重排

@JCStressTest
@Outcome(id = {"1", "4"}, expect = Expect.ACCEPTABLE, desc = "ok")
@Outcome(id = "0", expect = Expect.ACCEPTABLE_INTERESTING, desc = "!!!!")
@State
public class ConcurrencyTest {
    
    int num = 0;
    volatile boolean ready = false;
    
    @Actor
    public void actor1(I_Result r) {
        if(ready) {
            r.r1 = num + num;
        } else {
            r.r1 = 1;
        }
    }
    
    @Actor
    public void actor2(I_Result r) {
        num = 2;
        ready = true;
    }
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值