Java并发有序性

        Java并发算是一个比较高级的主题,但是这一块的知识又是高级工程师必须掌握的,骨头再难啃也得啃,希望本文的一些总结能帮助到希望深入了解Java并发的同学,哪怕是其中能有一点,能让你在阅读中有豁然开朗的感觉。

有序性

        首先举一个简单的例子

int a = 1;   ①
int b = 2;   ②
int c = a;   ③

        按我们的预期,执行的顺序应该是①②③,但是 真实的执行顺序可能是②①③或者①③②,这是因为指令重排序的原因,基本有二种重排序

  • CPU级的指令重排序

  • 编译器级的指令重排序

        重排序的目的是优化我们的程序运行速度,但是优化的前提是不能破坏as-if-serial语义。

        简单来说,以上面的例子为例,③由于有依赖①的结果,所以它需要永远排在①后面执行。 在单线程有序性还比较容易保证,但是在多线程情况就会变得复杂起来。所以JMM中抽象出了一个happen-before原则,这个原则是JMM给我们开发者的承诺,让我们写代码时对多线程情况下的有序性有一个正确的预期。

这个原则有下面5条

  • 同一个线程中,程序中前面的代码happen-before后面的代码

  • 对一个monitor的解锁happen-before对这个monitor的加锁

  • 对一个volatile变量的写happen-before对这个volatile变量的读

  • 线程start方法调用happen-before线程内的所有action

  • 在A线程调用了B线程的join,则B线程内的操作happen-before于A线程后续的操作

        当然happen-before具有传递性,如果A happen-before B, B happen-before C,则A 也 happen-before C。

        需要注意的是,happen-before并不完全等同于时间意义上的先执行,比如上面的例子中,根据第一条happen-before原则,int a = 1; 这条语句 happen-before int b = 2; 这条语句,但是由于二者之间没有依赖关系,可以指令重排,所以可以是 int b = 2;先执行,这是合法的,并不违背happen-before原则。

        理解这几条happen-before原则后,很多我们平时经常写的并发代码就有了理论依据,比如第二条,加锁happen-before解锁,所以保证了锁的同步范围内的代码,具有原子性和有序性,同时加锁和解锁都会插入内存屏障,可见性也得到保障,所以加锁后的代码是线程安全的。再比如第三条,volatile的写happen-before于volatile的读,有了这一条,多线程之间volatile修饰的共享变量的可见性得到保证。

        另外几条原则比较好理解,大家可以自行结合实际代码加深理解,这里就不赘述了。

Java学习视频

Java基础:

Java300集,Java必备优质视频_手把手图解学习Java,让学习成为一种享受

Java项目:

【Java游戏项目】1小时教你用Java语言做经典扫雷游戏_手把手教你开发游戏

【Java毕业设计】OA办公系统项目实战_OA员工管理系统项目_java开发

猜你喜欢

转载自blog.csdn.net/java_0000/article/details/125208835