JVM volatile语义:
mark:
(1)Java 内存模型不会对valatile指令的操作进行重排序:这个保证对volatile变量的操作时按照指令的出现顺序执行的。
(2)volatile变量不会被缓存在寄存器中(只有拥有线程可见)或者其他对CPU不可见的地方,每次总是从主存中读取volatile变量的结果。也就是说对于volatile变量的修改,其它线程总是可见的,并且不是使用自己线程栈内部的变量。也就是在happens-before法则中,对一个valatile变量的写操作后,其后的任何读操作理解可见此写操作的结果。
Volatile变量的读写
读:置本地数据无效,总是从主存中读取数据
写:更新本地数据,然后刷新主存中的数据
CAS操作:利用CPU中的特殊指令cmpxchg (intel)
CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
原子变量的实现:
首先变量是volatile的保证可见性;
对变量的更新在一个循环中实现,例如:
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
最少执行一次方法就可以返回,否则一直执行;
CAS的ABA问题
比如说一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且two进行了一些操作变成了B,然后two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后one操作成功。尽管线程one的CAS操作成功,但是不代表这个过程就是没有问题的。如果链表的头在变化了两次后恢复了原值,但是不代表链表就没有变化。因此前面提到的原子操作AtomicStampedReference/AtomicMarkableReference就很有
用了。这允许一对变化的元素进行原子操作。
Java通过Unsafe类通过JNI结合CPU的CAS指令来完成
sun.misc.natUnsafe.cc 的源码:
#include <gcj/cni.h> #include <gcj/field.h> #include <gcj/javaprims.h> #include <jvm.h> #include <sun/misc/Unsafe.h> #include <java/lang/System.h> #include <java/lang/InterruptedException.h> #include <java/lang/Thread.h> #include <java/lang/Long.h> #include "sysdep/locks.h" // Use a spinlock for multi-word accesses class spinlock { static volatile obj_addr_t lock; public: spinlock () { while (! compare_and_swap (&lock, 0, 1)) _Jv_ThreadYield (); } ~spinlock () { release_set (&lock, 0); } }; // This is a single lock that is used for all synchronized accesses if // the compiler can't generate inline compare-and-swap operations. In // most cases it'll never be used, but the i386 needs it for 64-bit // locked accesses and so does PPC32. It's worth building libgcj with // target=i486 (or above) to get the inlines. volatile obj_addr_t spinlock::lock; static inline bool compareAndSwap (volatile jint *addr, jint old, jint new_val) { jboolean result = false; spinlock lock; if ((result = (*addr == old))) *addr = new_val; return result; } static inline bool compareAndSwap (volatile jlong *addr, jlong old, jlong new_val) { jboolean result = false; spinlock lock; if ((result = (*addr == old))) *addr = new_val; return result; } static inline bool compareAndSwap (volatile jobject *addr, jobject old, jobject new_val) { jboolean result = false; spinlock lock; if ((result = (*addr == old))) *addr = new_val; return result; } jlong sun::misc::Unsafe::objectFieldOffset (::java::lang::reflect::Field *field) { _Jv_Field *fld = _Jv_FromReflectedField (field); // FIXME: what if it is not an instance field? return fld->getOffset(); } jint sun::misc::Unsafe::arrayBaseOffset (jclass arrayClass) { // FIXME: assert that arrayClass is array. jclass eltClass = arrayClass->getComponentType(); return (jint)(jlong) _Jv_GetArrayElementFromElementType (NULL, eltClass); } jint sun::misc::Unsafe::arrayIndexScale (jclass arrayClass) { // FIXME: assert that arrayClass is array. jclass eltClass = arrayClass->getComponentType(); if (eltClass->isPrimitive()) return eltClass->size(); return sizeof (void *); } // These methods are used when the compiler fails to generate inline // versions of the compare-and-swap primitives. jboolean sun::misc::Unsafe::compareAndSwapInt (jobject obj, jlong offset, jint expect, jint update) { jint *addr = (jint *)((char *)obj + offset); return compareAndSwap (addr, expect, update); } jboolean sun::misc::Unsafe::compareAndSwapLong (jobject obj, jlong offset, jlong expect, jlong update) { volatile jlong *addr = (jlong*)((char *) obj + offset); return compareAndSwap (addr, expect, update); } jboolean sun::misc::Unsafe::compareAndSwapObject (jobject obj, jlong offset, jobject expect, jobject update) { jobject *addr = (jobject*)((char *) obj + offset); return compareAndSwap (addr, expect, update); } void sun::misc::Unsafe::putOrderedInt (jobject obj, jlong offset, jint value) { volatile jint *addr = (jint *) ((char *) obj + offset); *addr = value; } void sun::misc::Unsafe::putOrderedLong (jobject obj, jlong offset, jlong value) { volatile jlong *addr = (jlong *) ((char *) obj + offset); spinlock lock; *addr = value; } void sun::misc::Unsafe::putOrderedObject (jobject obj, jlong offset, jobject value) { volatile jobject *addr = (jobject *) ((char *) obj + offset); *addr = value; } void sun::misc::Unsafe::putIntVolatile (jobject obj, jlong offset, jint value) { write_barrier (); volatile jint *addr = (jint *) ((char *) obj + offset); *addr = value; } void sun::misc::Unsafe::putLongVolatile (jobject obj, jlong offset, jlong value) { volatile jlong *addr = (jlong *) ((char *) obj + offset); spinlock lock; *addr = value; } void sun::misc::Unsafe::putObjectVolatile (jobject obj, jlong offset, jobject value) { write_barrier (); volatile jobject *addr = (jobject *) ((char *) obj + offset); *addr = value; } #if 0 // FIXME void sun::misc::Unsafe::putInt (jobject obj, jlong offset, jint value) { jint *addr = (jint *) ((char *) obj + offset); *addr = value; } #endif void sun::misc::Unsafe::putLong (jobject obj, jlong offset, jlong value) { jlong *addr = (jlong *) ((char *) obj + offset); spinlock lock; *addr = value; } void sun::misc::Unsafe::putObject (jobject obj, jlong offset, jobject value) { jobject *addr = (jobject *) ((char *) obj + offset); *addr = value; } jint sun::misc::Unsafe::getIntVolatile (jobject obj, jlong offset) { volatile jint *addr = (jint *) ((char *) obj + offset); jint result = *addr; read_barrier (); return result; } jobject sun::misc::Unsafe::getObjectVolatile (jobject obj, jlong offset) { volatile jobject *addr = (jobject *) ((char *) obj + offset); jobject result = *addr; read_barrier (); return result; } jlong sun::misc::Unsafe::getLong (jobject obj, jlong offset) { jlong *addr = (jlong *) ((char *) obj + offset); spinlock lock; return *addr; } jlong sun::misc::Unsafe::getLongVolatile (jobject obj, jlong offset) { volatile jlong *addr = (jlong *) ((char *) obj + offset); spinlock lock; return *addr; } void sun::misc::Unsafe::unpark (::java::lang::Thread *thread) { natThread *nt = (natThread *) thread->data; nt->park_helper.unpark (); } void sun::misc::Unsafe::park (jboolean isAbsolute, jlong time) { using namespace ::java::lang; Thread *thread = Thread::currentThread(); natThread *nt = (natThread *) thread->data; nt->park_helper.park (isAbsolute, time); }
相关推荐
Java并发编程系列- volatile;Java并发编程系列- volatile;Java并发编程系列- volatile;Java并发编程系列- volatile;Java并发编程系列- volatile;
Java并发编程:volatile关键字解析
Java并发编程(5)volatile变量修饰符—意料之外的问题(含代码)编程开发技术共6页.pdf.zip
Java 多线程与并发(5_26)-关键字_ volatile详解
3.1.4 Volatile变量 3.2 发布与逸出 3.3 线程封闭 3.3.1 Ad-hoc线程封闭 3.3.2 栈封闭 3.3.3 ThreadLocal类 3.4 不变性 3.4.1 Final域 3.4.2 示例:使用Volatile类型来发布不可变对象 3.5 安全发布 3.5.1...
volatile的使用优化:共享变量会被频繁读写时,可以通过追加为64字节以提高并发编程的效率。因为目前主流处理器高速缓存行是64个字节宽,不支持部分填充缓存行,通过追加到64字节的方式填满高速缓冲区的缓存行,避免...
本文的主题是关于具有java语言风格的Thread、synchronized、volatile,以及J2SE5中新增的概念,如锁(Lock)、原子性(Atomics)、并发集合类、线程协作摘要、Executors。开发者通过这些基础的接口可以构建高并发、线程...
本书全面介绍了如何使用Java 2平台进行并发编程,较上一版新增和扩展的内容包括:, ·存储模型 ·取消 ·可移植的并行编程 ·实现并发控制的工具类, Java平台提供了一套广泛而功能强大的api,工具和技术。...
3.1.4 Volatile变量 3.2 发布与逸出 3.3 线程封闭 3.3.1 Ad-hoc线程封闭 3.3.2 栈封闭 3.3.3 ThreadLocal类 3.4 不变性 3.4.1 Final域 3.4.2 示例:使用Volatile类型来发布不可变对象 3.5 安全发布 3.5.1...
并发编程-volatile使用精讲.pdf
描述java并发编程原理 一.内存模型的相关概念 二.并发编程中的三个概念 三.Java内存模型 四..深入剖析volatile关键字 五.使用volatile关键字的场景
java并发方面的两大名著之一。读者将通过使用java.lang.thread类、synchronized和volatile关键字,以及wait、notify和notifyall方法,学习如何初始化、控制和协调并发操作。此外,本书还提供了有关并发编程的全方位...
java并发编程 基础知识,守护线程与线程, 并行和并发有什么区别? 什么是上下文切换? 线程和进程区别 什么是线程和进程? 创建线程有哪几种方式?,如何避免线程死锁 线程的 run()和 start()有什么区别? 什么是 ...
多种创建线程的方式案例演示(一)带返回值的方式.mp4 多种创建线程的方式案例演示(二)使用线程池.mp4 Spring对并发的支持:Spring的异步任务.mp4 使用jdk8提供的lambda进行并行计算.mp4 了解多线程所带来的安全...
7、并发工具类CountDownLatch 、CyclicBarrier和Semaphore底层实现原理 8、线程池原理和如何使用线程池 9、ThreadLocal 为什么会内存泄漏 10、Volatile底层实现原理 11、AQS源码分析 12、CAS原理分析和使用场景 13、...
资源概要:1,多线程;2,synchronized;3,volatile;4,多线程在JVM中的实现...原子类Atomic-CAS及其实现原理 锁Lock-AQS核心原理剖析 并发工具类、并发容器、阻塞队列 线程池原理剖析 线程池案例-Web容器-压力测试
龙果 java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四...
主要介绍了Java并发编程-volatile可见性详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧