Java并发编程的艺术-第三章之Java内存模型

并发编程模型的关键问题

在并发编程中,须要处理2个关键的问题:线程间如何通讯和线程之间如何同步。编程

线程之间的同通讯机制有2种:共享内存和消息传递。多线程

同步:程序中用于控制不一样线程间操做发生相对顺序的机制。并发

       Java并发采用的是共享内存的模型,同步是显示进行的,就是程序必须显示指定(用synchronized、volatile、final)某个方法或某段代码须要在线程之间是互斥的。Java 线程之间通讯有Java内存模型(JMM)控制,JMM经过控制主内存与每一个线程的本地内存之间的交互,来为保证内存可见性。函数

 

重排序

重排序是指编译器和处理器为了优化程序的性能而对指令序列进行从新排序的一种手段。重排序不会改变单线程的执行结果,可是能够会改变多线程的执行结果。性能

顺序一致性

若是程序是正确同步的,程序的执行结果具备顺序一致性,即,程序的执行结果与其在顺序一致性模型中执行的结果是一致的。优化

 

经常使用的同步原语包括synchronized、volatile、final,下面主要介绍它们的原理spa

 

Volatile

Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。并且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任什么时候刻,两个不一样的线程老是看到某个成员变量的同一个值。线程

使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,没必要使用。
因为使用volatile屏蔽掉了VM中必要的代码优化,因此在效率上比较低,所以必定在必要时才使用此关键字。 对象

先写出volatile特色:排序

可见性:对于一个volatile变量的读,总能看到任意线程对这个volatile变量最后的写入。

原子性:对于任意单个volatile变量的读写具备原子性,可是相似于volatile++这种复合操做不具有原子性。

有序性:主要是禁止指令重排序。

适应场景:单个线程写,多个线程读。提供一种比锁更轻量级的通讯机制。在功能上锁比volatile功能更强大,可提供整个临界区代码的执行具备原子性。在执行性能上,volatile更有优点。因此若是想用volatile替代锁,要注意场景:1)对变量的写操做不依赖于当前值,2)该变量没有包含在具备其余变量的不变式中。其实就是为了保证操做是原子性的。

 

Synchronized(锁)

锁是Java并发编程中最重要的同步机制,锁可让临界区互斥,还可让释放锁的线程向获取同一个锁的线程发送消息。从内存语义上看:释放锁和volatile的写相同、获取锁和volatile的读相同。都是经过主内存发送消息相互通讯的。


final

与锁和volatile相比,对final域的读写更像是普通变量的访问,下面介绍final域的内存语义:
对于final域,编译器和处理器要遵循两个重排序规则:

一、在构造函数内对一个final域的写入,与随后把这个被构造函数对象的引用赋值给一个引用变量,这两个操做之间不能重排序;

这样能够保证对象引用为任意线程可见以前,保证对象的final域已经被正确的初始化了,而普通的域没有这个保障。

 

二、初次读一个包含final域的对象的引用,与随后初次读这个fina域,这两个操做不能重排序。

这样能够保证在读一个对象的final域以前,必定会先读包含这个对象的引用,防止在读普通的域时,这个域尚未被写线程写入。

相关文章
相关标签/搜索