本篇博文,主要集中并发编程的三个问题:可见性、原子性、有序性。数据库
只讲理论,不谈如何解决。编程
说白了并发编程中的三个问题,就是先辈们给咱们这些后辈留下来的坑!缓存
相信大部分人都知道,一台计算机的组成包括但不限于:CPU、内存、显卡….安全
在这里, 笔者将计算机中的组抽象成几类,即:CPU、I/O设备、内存微信
有了以上三个分类,笔者接下来的文章就好写了。(滑稽)多线程
讲道理,在处理速度方面CPU >> 内存 >> I/O设备
。并发
这时候, 为了充分发挥CPU的计算速度, 硬件方面则是在CPU和内存之间, 增长了一种叫高速缓存的技术。学习
总而言之,高速缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾。优化
固然, 在单核时代Cpu缓存并无出现数据一致性问题, 可是在多核时代就不同了。操作系统
在多核处理器中,因为Cpu并不与内存直接打交道, 而是经过高速缓存。
同理, 内存也是并不直接与Cpu打交道,也是经过高速缓存与Cpu打交道。
缓存一致性问题以及解决方案,网上一搜一大堆,笔者在此就不作过多的叙述。
因此,只须要记住结论便可:
Cpu缓存不一致为并发编程带来----可见性问题。(结论)
在之前的印象中,说到原子性,笔者张口就是:原子操做是一个不可分割的总体, 该总体中的全部指令,要么所有执行, 要么所有不执行, 没有中间状态。
在此,笔者所写的原子性概念,仿佛过于宽泛和缥缈。并且,原子性在不一样的使用场景,也有可能含义并不相同。
接下来,咱们试着从数据库事务和并发编程两个方面来进行对比:
在数据库中,原子性概念以下:
在并发编程中,原子性概念以下:
从上文中能够看出,并发编程和数据库二者之间的原子性概念有些类似。
都是强调,一个原子操做不能被打断!!
因此,上下文切换给并发编程带来——原子性问题。(结论)
讲道理,在计算机语言中,高级语言的运行都须要经过编译器转换成机器语言,经过机器语言在计算机上运行。
那么,在编译器中为了提升运行速度,会对内存访问的有关操做(读&写)作一种优化,即指令的重排序。这种重排序在单线程环境下,不影响结果的正确性。可是,在多线程环境下可能会对结果的正确性产生影响。
指令的重排序,是形成并发编程的有序性问题的缘由。
编译器带来指令重排序,而指令重排序形成有序性问题。
编译器优化—带来—> 指令重排序—带来—>有序性问题
因此,编译器的优化给并发编程带来—有序性问题!
最后,本篇博文,主要是对刚学习并发编程的朋友,提出并发编程的三个问题的概念。
说实话,笔者刚开始学的时候,并无想过想过原子、有序、可见性的形成缘由,直接通通死记硬背!
有时候想一想,以为本身挺好笑的。
总之,读者们要记住,整个Java并发包的设计与实现,都是为了解决并发编程的可见、原子、有序三个问题。
接下来,笔者会尝试着写写,Java是如何解决可见性、原子性和有序性的….