原子性、可见性、有序性

Java内存模型是围绕着在并发过程中如何处理原子性可见性、和有序性这三个特征来建立的。

原子性

Java内存模型要求lockunlockreadloadassignusestorewrite这八个操作都具有原子性。

Java内存模型直接保存的原子性变量操作有readloadassignusestorewrite;大致可认为基本数据类型longdouble)的访问读写具备原子性。

Java内存模型还提供了lockunlock操作来保证更大范围的原子操作,虚拟机未把lockunlock操作直接开放给用户使用,但提供了更高层次的字节码指令monitorentermonitorexit来隐式使用这个操作,这两个字节码指令反映到Java代码中就是同步块synchronized关键字。

可见性

当一个线程修改了共享变量值,其他线程能够立即得知这个修改。Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方式类实现可见性,普通变量和volatile变量都是如此。

普通变量与volatile变量区别:volatile保证了新值能立即同步到主内存,每次使用前立即从主内存刷新,保证了多线程操作时变量的可见性;

volatile外,Java还可以通过synchronizedfinal关键字来实现可见性;同步块的可见性是在一个变量执行unlock操作之前,必须先把此变量同步回主内存中;final可见性是指,被final修饰的字段在构造器中一旦初始化完成,并且构造器没有this引用逃逸,在其他线程中能看见final字段的值。

有序性

如果在同一线程中所有操作都是有序的,如果在一个线程中观察另一个线程所有操作都是无序的,前半句是指线程内表现为串行语义,后半句指指令重排序现象和工作内存与主内存同步延迟现象。

volatilesynchronized都能保证线程之间操作的有序性,volatile关键字本身包含了禁止指令重排序语义,而synchronized则是由一个变量在同一个时刻只允许一条线程对其进行lock操作,保证了持有同一个锁的两个同步块只能串行进入。

long和double变量的特殊规则

虚拟机允许将没有被volatile修饰的64位数据的续写操作划分为两次32位操作,即允许虚拟机实现选择可以不保证64位数据类型的loadstorereadwrite四个操作的原子性

若多个线程共享一个未被声明为volatilelongdouble类是变量,并行读取修改,某些线程可能读取到一个既非原值,但这种情况非常罕见,且商用Java虚拟机中不会出现,Java内存模型虽然允许虚拟机不把longdouble变量的读写实现为原子操作,但允许虚拟机选择把这些操作实现为具有原子性的操作。