可见性、有序性与原子性以及非原子协定

        介绍完Java内存模型的相关操作与规则,会发现其主要就是围绕着在并发过程中如何处理原子性、可见性和有序性这三个特征来建立的,这也是并发编程最核心的核心概念。

可见性

        可见性是指在并发环境下,当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。

在多核处理器的架构中,由于CPU缓存的存在,当某一核心修改了共享变量的值,并不一定会立即刷新回主内存,而且就算立即刷新回了主内存,其他同样使用该共享变量的线程也不一定会立刻感知到其数据的变化从而重新从主内存加载共享变量。

在Java中,有如下几种手段可以保证并发可见性(其实说到底最底层都是通过设置内存屏障来实现的)。

1. volatile关键字。 volatile修饰的变量保证新值能够立即同步到主内存,以及每次使用前都立即从主内存刷新。

2. synchronized以及Lock显示锁。根据JMM内存交互规则:对一个变量执行unlock操作之前,必须先把此变量同步回主内存,对一个变量执行lock操作之前,将会清空工作内存中该变量的值,重新从主内存加载。

3. final关键字。被final修饰的字段在构造器中一旦被初始化完成并且在初始化的过程中没有把“this”的引用传递出去,那么其他线程就能看的final字段的值。

4. 原子变量。类似AtomicInteger这样的原子变量,其实内部借助了volatile关键字。

5. 其他一切遵循happens-before先行发生原则的操作过程,当然其实上面提到的所有手段都属于此类。

 

有序性 

有序性其实有以下几层语义:

1. 单线程内部数据不相关的操作由于指令重排序导致的问题。

       在 Java内存模型JMM之四volatile关键字 章节中关于有序性描述的内容,初始化完成之后的标识变量的重排序就会导致另一个线程的执行出现错误。针对该问题可以使用Volatile关键字解决。

2. 多线程并发执行的无序性。

       多线程对于临界区代码的无序执行就该该问题的体现。使用synchronized关键字、Lock显式锁对临界区进行加锁,即可时多线程串形执行临界去代码。

3. 由于修改共享变量之后的可见性不能保证导致的程序执行结果无法达到预期的变相的有序性问题。

       笼统地说,这是“工作内存或者处理器缓存与主内存同步延迟”现象导致的一系列问题,严格来说第1条也属于此类,只是此处的描述的问题更广泛。满足happens-before先行发生原则的操作将会是这类问题的统一判断标准,在不能通过先行发生原则推导出有明确的有序性来的情况下,可以使用synchronized关键字、Lock显式锁解决所有问题。

 

原子性

原子性是指某个(些)操作在语意上是原子的。即一个操作或者多个操作要么全部执行并且执行的过程不会被任何因素打断(包含CPU暂停调度),要么就都不执行。 如果一个操作是原子性的, 那么在多线程环境下, 就不会出现在操作的过程中变量被其他线程修改等奇怪的问题。比如对单个变量的读或者写操作是原子操作,因为读或者写这样的操作在计算机底层指令级是原子的,对某个内存地址的指令操作在同时时刻只能被一个指令独享。另外根据上一章我知道CAS操作也是原子操作。

        在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作。这看起来简单,其实理解起来并不是那么容易。看下面一个例子:

 

x = 10; //语句1

y = x; //语句2

x++; //语句3

x = x + 1; //语句4
 以上4个语句,其实只有语句1是原子操作,它直接数值10写入到工作内存中。要保证非原子的操作具有原子性,可以使用 synchronized关键字、 Lock显式锁来达到整个操作的原子性。

 

非原子协定

上面提到对基本类型的变量的读写操作是原子操作,但是对于64位的数据类型longdouble却并不一定满足。因为在JMM内存模型中特别定义了一条宽松的规定:允许JVM虚拟机将没有被volatile修饰的64位数据的读写操作划分为两次32位的操作两进行。 

所以对 long和double类型的变量的读写操作不保证一定是原子操作,这就是所谓的long和double的非原子协定。所以当多个线程同时对一个并未声明为volatile的long或者double变量进行读取或者修改操作,那么某些线程将可能会读取到一个既非原值,也不是其他线程修改值的代表了“半个变量”的数值,当然这种情况非常罕见。因为大多数平台下的JVM虚拟机都还是选择了把64位数据的读与写操作实现为原子操作的。

 

 

综上总结

synchronized关键字、Lock对象同时支持原子性、有序性和可见性。 

volatile关键字只支持可见性和有序性,并不保证原子性。

 

猜你喜欢

转载自pzh9527.iteye.com/blog/2414628