关于多线程中可能出现的问题

一.内存模型的相关概念(高速缓存是每个线程特有的,也称本地缓存)
 大家都知道,计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入。
 由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执行速度很快,而从内存读取数据和向内存写入数据的过程跟CPU执行指令的速度比起来要慢的多,因此如果任何时候对数据的操作都要通过和内存的交互来进行,会大大降低指令执行的速度。因此在CPU里面就有了高速缓存

二.并发编程中的三个概念
在并发编程中,我们通常会遇到以下三个问题:原子性问题,可见性问题,有序性问题
  1.原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
例如,如果i=32;不具备原子性的话,当给它的低16赋值完时,突然中断,其他线程在去读这个值时,就是错误的值.

  2.可见性:指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
这就是可见性问题,线程1对变量i修改了之后,线程2没有立即看到线程1修改的值。

  3.有序性:即程序执行的顺序按照代码的先后顺序执行,首先什么是指令重排序,一般来说,处理器为了提高程序运行效率,可能会对输入代码进行优化,
它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。处理器在进行重排序时也是会考虑指令之间的数据依赖性
  指令重排序不会影响单个线程的执行,但是会影响到线程并发执行的正确性。

三.Java内存模型
  在Java虚拟机规范中试图定义一种Java内存模型(Java Memory Model,JMM)来屏蔽各个硬件平台和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果。那么Java内存模型规定了哪些东西呢,它定义了程序中变量的访问规则,往大一点说是定义了程序执行的次序。注意,为了获得较好的执行性能,Java内存模型并没有限制执行引擎使用处理器的寄存器或者高速缓存来提升指令执行速度,也没有限制编译器对指令进行重排序。也就是说,在java内存模型中,也会存在缓存一致性问题和指令重排序的问题。

对并发编程中常见的三问题JMM的解决方法:
1.原子性:
  在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行。
例如:
  int i = 10; 是原子操作.
  int j = i; 不是原子操作
可以通过synchronized和Lock来实现。由于synchronized和Lock能够保证任一时刻只有一个线程执行该代码块,
那么自然就不存在原子性问题了,从而保证了原子性。

2.可见性
  对于可见性,Java提供了volatile关键字来保证可见性。
  另外,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,
并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。

3.有序性
  在Java里面,可以通过volatile关键字来保证一定的“有序性”,因为可以禁止指令重排序。
  另外可以通过synchronized和Lock来保证有序性,
  很显然,synchronized和Lock保证每个时刻是有一个线程执行同步代码,相当于是让线程顺序执行同步代码,自然就保证了有序性。

补充:外,Java内存模型具备一些先天的“有序性”,即不需要通过任何手段就能够得到保证的有序性,这个通常也称为 happens-before 原则。
如果两个操作的执行次序无法从happens-before原则推导出来,那么它们就不能保证它们的有序性,虚拟机可以随意地对它们进行重排序。

posted @ 2020-03-22 14:21  whhhd  阅读(1791)  评论(0编辑  收藏  举报