• 欢迎来到本博客,希望可以y一起学习与分享

Java并发小结(一) — 基本概念

Java benz 来源:Java并发小结(一) -- 基本概念 4年前 (2018-04-09) 136次浏览 0个评论 扫描二维码
文章目录[隐藏]

这里整理下Java并发中的基本概念,以及个人的理解。

并发与并行

并行,指的是一个工作者同时做多件事情;并发指的是同一时刻多个工作者做多件事情。
对应到系统,比如说单个CPU,并行就是指单个CPU同时执行多个线程,在同一时间点,只会执行一个线程;并发指的是多个CPU同时执行多个线程。并发一定是并行的,并行的不一定是并发的。

内存可见性

这个概念初看,很容易就产生个疑问:难道内存还有不同见的情况?的确会有,需要了解这个问题,那就需要先了解下Java的内存模型:

线程、主内存、工作内存之间的关系如上图所示。 工作内存与主内存之间如果不同步,就会造成内存可见性问题: 如果线程A对共享变量X进行了修改,但是线程A没有及时把更新后的值刷入到主内存中,而此时线程B从主内存读取共享变量X的值,所以X的值是原始值,那么我们就说对于线程B来讲,共享变量X的更改对线程B是不可见的。

指令重排序

指令重排序包含两个方面:编译器重排与运行期重排。

  • 编译期重排。编译源代码时,编译器依据对上下文的分析,对指令进行重排序,以之更适合于CPU的并行执行。
  • 运行期重排,CPU在执行过程中,动态分析依赖部件的效能,对指令做重排序优化。

单看指令重排序这个概念,如果没有一定的限制,很明显指令重排序会使程序陷入混乱,没有办法理解,那怎么去限制指令重排序的范围呢,这个就要看下happens-before了。happens-before是在Java内存模型中定义好的, 在以下八种情况下,通过增加内存屏障指令,限制了指令重排序的范围:

  • 同一个线程中的每个Action都happens-before于出现在其后的任何一个Action。
  • 对一个监视器的解锁happens-before于每一个后续对同一个监视器的加锁。
  • 对volatile字段的写入操作happens-before于每一个后续的同一个字段的读操作。
  • Thread.start()的调用会happens-before于启动线程里面的动作。
  • Thread中的所有动作都happens-before于其他线程检查到此线程结束或者Thread.join()中返回或者Thread.isAlive()==false。
  • 一个线程A调用另一个另一个线程B的interrupt()都happens-before于线程A发现B被A中断(B抛出异常或者A检测到B的isInterrupted()或者interrupted())。
  • 一个对象构造函数的结束happens-before与该对象的finalizer的开始
  • 如果A动作happens-before于B动作,而B动作happens-before与C动作,那么A动作happens-before于C动作。

volatile

可以使用volatile变量来解决内存可见性的问题,volatile描述符的主要作用:

  • 保证被volatile修饰的共享gong’x变量对所有线程总数可见的,也就是当一个线程修改了一个被volatile修饰共享变量的值,新值总数可以被其他线程立即得知。
  • 禁止指令重排序优化。
  • 不能保证volatile变量符合操作的原子性。

原子性

这个概念在数据库里也有,一个操作要确保原子性,这个操作不能出现中间状态,要么操作全部成功,要么操作全部失败。比如a++,这个操作实际内部需要“读a->计算a+1->设置a”。要确保这个操作是原子性的,其它线程在对a进行操作时,只能在a++之前或之后对a进行操作,而不能在读 a之后或者设置a之前对a进行操作。


文章 Java并发小结(一) — 基本概念 转载需要注明出处
喜欢 (0)

您必须 登录 才能发表评论!