首先介绍一下什么是Compare And Swap(CAS)?简单的说就是比较并交换。
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。” Java并发包(java.util.concurrent)中大量使用了CAS操作,涉及到并发的地方都调用了sun.misc.Unsafe类方法进行CAS操作。
在看一下volatile, Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的值是相同的,更简单一点理解就是volatile修饰的变量值发生变化时对于另外的线程是可见的。
如何正确使用volatile可以参考下面这篇文章:
http://www.ibm.com/developerworks/cn/java/j-jtp06197.html Java 理论与实践: 正确使用 Volatile 变量
下面来看看java中具体的CAS操作类sun.misc.Unsafe。Unsafe类提供了硬件级别的原子操作,Java无法直接访问到操作系统底层(如系统硬件等),为此Java使用native方法来扩展Java程序的功能。具体实现使用c++,详见文件sun.misc.natUnsafe.cc();sun.misc包的源代码可以在这里找到:
http://www.oschina.net/code/explore/gcc-4.5.2/libjava/sun/misc
//下面是sun.misc.Unsafe.java类源码
package sun.misc;
import java.lang.reflect.Field;
public class Unsafe
{
// Singleton class.
private static Unsafe unsafe = new Unsafe();
private Unsafe()
{
}
public static Unsafe getUnsafe()
{
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPropertiesAccess();
return unsafe;
}
public native long objectFieldOffset(Field field);
public native boolean compareAndSwapInt(Object obj, long offset,
int expect, int update);
public native boolean compareAndSwapLong(Object obj, long offset,
long expect, long update);
public native boolean compareAndSwapObject(Object obj, long offset,
Object expect, Object update);
public native void putOrderedInt(Object obj, long offset, int value);
public native void putOrderedLong(Object obj, long offset, long value);
public native void putOrderedObject(Object obj, long offset, Object value);
public native void putIntVolatile(Object obj, long offset, int value);
public native int getIntVolatile(Object obj, long offset);
public native void putLongVolatile(Object obj, long offset, long value);
public native void putLong(Object obj, long offset, long value);
public native long getLongVolatile(Object obj, long offset);
public native long getLong(Object obj, long offset);
public native void putObjectVolatile(Object obj, long offset, Object value);
public native void putObject(Object obj, long offset, Object value);
public native Object getObjectVolatile(Object obj, long offset);
public native int arrayBaseOffset(Class arrayClass);
public native int arrayIndexScale(Class arrayClass);
public native void unpark(Thread thread);
public native void park(boolean isAbsolute, long time);
}
//下面是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);
}
====================================
Sun.misc.Unsafe介绍
首先介绍一下什么是Compare And Swap(CAS)?简单的说就是比较并交换。
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。” Java并发包(java.util.concurrent)中大量使用了CAS操作,涉及到并发的地方都调用了sun.misc.Unsafe类方法进行CAS操作。
再介绍一下什么是JNI,JNI是Java Native Interface的缩写,中文为JAVA本地调用。使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少保证本地代码能工作在任何Java虚拟机实现下。Unsafe类中的提供的CAS操作方法都是通过JNI来实现.
在看一下volatile, Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的值是相同的,更简单一点理解就是volatile修饰的变量值发生变化时对于另外的线程是可见的。
如何正确使用volatile可以参考下面这篇文章:
http://www.ibm.com/developerworks/cn/java/j-jtp06197.html Java 理论与实践: 正确使用 Volatile 变量
下面来看看java中具体的CAS操作类sun.misc.Unsafe。Unsafe类提供了硬件级别的原子操作,Java无法直接访问到操作系统底层(如系统硬件等),为此Java使用native方法来扩展Java程序的功能。具体实现使用c++,详见文件sun.misc.natUnsafe.cc;sun.misc包的源代码可以在这里找到:
http://www.oschina.net/code/explore/gcc-4.5.2/libjava/sun/misc
更多详情请点击
博客原文地址: http://zeige.iteye.com/blog/1182571
源码剖析之sun.misc.Unsafe
最新推荐文章于 2022-03-31 10:10:20 发布