源码剖析之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操作。

在看一下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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值