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并发编程实践中,第八章主要探讨了原子变量和非阻塞算法在处理并发问题时的重要性和优势,以克服传统锁机制的局限性。锁在多线程环境下提供了对共享资源的互斥访问,但同时也存在一些明显的劣势。 首先,锁的...
8. **原子操作类**:`java.util.concurrent.atomic`包下的原子类如`AtomicInteger`、`AtomicReference`等,提供了一种无锁编程的方式,通过CAS(Compare and Swap)操作来更新变量,保证了操作的原子性。 9. **死锁...
6. **原子操作与CAS**:Atomic类提供了一种无锁编程的方式,利用硬件级别的比较并交换(Compare and Swap, CAS)操作实现原子性更新,以提高并发性能。 7. **线程池设计**:线程池可以有效管理并发线程,避免频繁...
Java 语言提供了多种原子操作,包括 Atomic 变量、 Compare-And-Swap(CAS)操作等。 7. 并发集合 并发集合是 Java 语言中的一种特殊集合,用于在多线程环境下存储和操作数据。Java 语言提供了多种并发集合,包括 ...
再者,`java.util.concurrent.atomic`包中的原子类提供了非阻塞的线程安全操作,如`AtomicInteger`、`AtomicLong`等,它们使用CAS(Compare and Swap)操作实现无锁编程,提高了并发性能。 最后,死锁、活锁和饥饿...
此外,`java.util.concurrent.atomic`包中的原子类提供了在无同步的情况下实现线程安全操作的方式,它们使用CAS(Compare and Swap)操作来保证原子性,适用于轻量级同步需求。 Java并发编程还包括对并发集合的理解...
Java并发编程是Java语言中最为复杂且重要的部分之一,它涉及了多线程编程、内存模型、同步机制等多个领域。为了深入理解Java并发编程,有必要了解其核心技术点和相关实现原理,以下将详细介绍文件中提及的关键知识点...
在Java编程领域,并发编程是不可或缺的一部分,尤其是在大型系统或高并发应用中。"java并发编程-构建块"这个主题涵盖了使程序能够同时处理多个任务的关键概念和技术。在这个主题下,我们将深入探讨Java中用于构建...
6. **原子操作与CAS**:Java的`java.util.concurrent.atomic`包提供了原子变量类,如AtomicInteger、AtomicReference等。它们使用无锁的CAS(Compare and Swap)算法实现线程安全的更新,具有高效率和低开销的特点。...
4. **原子操作与CAS**:`java.util.concurrent.atomic`包中的原子变量类如`AtomicInteger`提供了无锁编程的能力。比较和交换(CAS)操作是其底层实现的关键,理解CAS的工作原理可以帮助你编写更高效的并发代码。 5....
`java.util.concurrent.atomic`包提供了原子变量类,如AtomicInteger和AtomicReference,它们通过CAS(Compare and Swap)无锁算法实现线程安全的更新操作。 10. **中断和异常处理** Thread类的interrupt()方法...
2. **同步机制**:Java的同步机制是并发编程的核心,包括synchronized关键字、wait/notify机制以及volatile变量。通过这些机制,开发者可以确保数据的一致性和避免竞态条件。 3. **并发集合**:Java并发集合库提供...
《实战Java高并发程序设计》第二版是一本深入探讨Java多线程和并发编程的书籍。这本书涵盖了Java并发编程的核心概念和技术,旨在帮助开发者在实际项目中高效地处理高并发场景。随书附带的代码提供了丰富的示例,以便...
- 应用CAS(Compare and Swap)算法,如Java的Atomic类,以原子方式更新数据,减少锁的使用。 - 减少不必要的线程创建,避免线程闲置。 - 使用协程,单线程内调度多任务,减少线程间的切换。 5. **防止死锁**: ...
根据提供的标题、描述和标签,本文将围绕“Java并发编程实践”这一主题展开,深入探讨Java并发编程的基础概念、核心原理以及实际应用技巧。 ### 一、Java并发编程概述 Java并发编程是Java开发中一个非常重要的领域...
我们可以通过使用synchronized关键字、volatile关键字、Lock接口、Atomic变量等方式来实现线程安全。 并发编程的三要素是:线程、进程和上下文切换。线程是操作系统中的一种基本执行单元,进程是操作系统中的一种...
《Java并发编程实践》这本书是Java开发者深入理解并发编程的重要参考资料。并发编程是现代软件开发中的核心技能之一,尤其是在多核处理器普及后,利用并发能够极大地提升程序的执行效率。以下将根据提供的章节标题,...