Java并发-再探JMM

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/zhangdong2012/article/details/100003475

Java内存模型

个人理解,Java内存模型应该是Java并发编程中最难理解的一个概念之一。由于最近准备换工作,所以,按照惯例有复习了一下Java并发相关的知识(《Java并发编程的艺术》以及极客时间王宝令老师的《Java并发编程实战》),在复习的过程中,我发现《Java并发编程的艺术》中介绍JMM时,引入了很多晦涩难懂的知识,比如内存屏障等等,让人看的一头雾水,所以决定从更加宏观的角度去总结JMM相关的知识。

并发编程的主要目的是榨取计算机的性能,但由于硬件上cpu/内存/磁盘的数据读写速度相差太大,所以引入了cpu换成、分时处理、指令乱序优化等,但这也给并发编程带来了麻烦,比如:

  • cpu引入缓存虽然解决了cpu运算速度与内存读写速度的不匹配问题,但是带来了内存可见性问题;
  • cpu分时造成的线程切换带来了原子性问题;
  • 乱序优化带来了程序执行的顺序性问题;

综上所述,并发编程问题的三个核心根源在于:可见性问题、原子性问题和有序性问题。

为了解决这个问题,Java引入了Java内存模型,简单理解,Java内存模型就是一系列的规范,这些规范对计算机的优化进行了限制,以保证程序的正确性,而在java中,这些规范就是通过volatile、synchronized、final等来体现的,也就是说,volatile、synchronized和final为程序员提高了实施这些规范的入口。

在王宝令老师的专栏中,归纳了以下几条规则:

  • 程序的顺序性规则
int x = 42;
boolean y = true;

这里的第一条语句happens-before与第二条;

  • 对volatile变量的写happens-before于后续对该变量的读;
  • a happens-before b,b happens-before c,那么 a happens-before c;
  • 线程的start()规则;
主线程A在启动子线程B后,子线程B能看到主线程A的操作
  • 线程的join()规则;
主线程A在子线程B完成后,能够看到子线程B的操作

这里的happens-before不是A先于B发生的意思,而是A执行后产生的变化对B可见,这两者还是有差异的。

那么,下面我们在将这些规则对应到java中,volatile保证了内存可见性,synchronized解决了原子性问题,同时也可以保证内存可见性,volatile、synchronized、final共同约束了编译器优化,保证程序执行的顺序性,即解决了顺序性问题。其实这之间是存在交叉了,而不是独立存在。

至此,java内存模型就可以理解到这里,再深入下去,很容易混乱。

线程的状态

  • 初始状态;
  • 可运行状态;
  • 运行状态;
  • 休眠状态;
  • 终止状态;

等待通知模型

synchronized(对象) {
	while(条件不满足){
    	 对象.wait();
	}
}


synchronized(对象) {
    改变条件;
    对象.notifyAll();
}

到此,《Java并发编程的艺术》的前四章就学完了。

猜你喜欢

转载自blog.csdn.net/zhangdong2012/article/details/100003475
今日推荐