`
grzrt
  • 浏览: 188861 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

源码剖析之sun.misc.Unsafe

    博客分类:
  • JAVA
 
阅读更多

首先介绍一下什么是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

分享到:
评论

相关推荐

    JDK8中sun.misc下UnSafe类源代码 UnSafe.java

    《深入解析JDK8中的sun.misc.UnSafe类》 在Java编程中,sun.misc.UnSafe类是一个非常特殊的存在。这个类在JDK8中扮演着一个核心的角色,它提供了对Java语言规范中未公开的底层操作的访问。尽管UnSafe类并非设计为...

    JDK8中sun.misc包下的UnSafe类

    JDK8中sun.misc包下的UnSafe类,想查看源码的就拿走,没积分的请与我联系!xtfggef@gmail.com

    sun.misc.BASE64Encoder源码及jar包

    在Java编程语言中,`sun.misc.BASE64Encoder`和`BASE64Decoder`是用于进行Base64编码和解码的内部类,它们属于`sun.misc`包,这是一个非公开(非标准)的Java库。`sun.misc`包中的类主要用于JVM内部使用,因此在官方...

    sun.misc.BASE64Decoder和sun.misc.BASE64Encoder不可用已解决

    最近项目实验发现导入工具程序后项目有错,查看发现sun.misc.BASE64Decoder和sun.misc.BASE64Encoder不可用,找不到相应的类。 二、原因分析 冲浪后发现JDK中的lib\tools.jar和JRE中的lib\rt.jar已从Java SE 9中...

    sun.misc.Unsafe源码

    《深入解析Java sun.misc.Unsafe》 在Java编程语言中,`sun.misc.Unsafe`类是一个神秘而强大的工具,它提供了对内存的直接操作和访问,绕过了Java的一些安全限制。这个类通常不被推荐在生产环境中直接使用,因为它...

    sun.misc.BASE64Decoder(Android Base64Jar包以及Java源代码)

    sun.misc.BASE64Decoder 其中包括 Android Base64Jar包 以及Java源代码 sun.misc.BASE64Decoder 其中包括 Android Base64Jar包 以及Java源代码 sun.misc.BASE64Decoder 其中包括 Android Base64Jar包 以及...

    sun.misc.BASE64Encoder 加密源码+完整包.rar

    在Java编程语言中,`sun.misc.BASE64Encoder` 和 `sun.misc.BASE64Decoder` 是两个用于Base64编码和解码的内部类,它们位于`sun.misc`包下。Base64是一种用于在网络上传输二进制数据的文本编码方式,它将任意的字节...

    sun.misc.BASE64Encoder.jar包

    `sun.misc.BASE64Encoder`和`sun.misc.BASE64Decoder`就是这样的两个类,它们分别用于Base64编码和解码。 Base64是一种用于将二进制数据转换为可打印ASCII字符的编码方式,常用于在网络上传输二进制数据,如电子...

    sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder;

    标题 "sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder;" 暗示了我们正在讨论Java中用于Base64编码和解码的类。这两个类,`BASE64Decoder`和`BASE64Encoder`,是Java早期版本中的非标准组件,属于`sun.misc`...

    sun.misc.base64decoder.jar下载

    sun.misc.BASE64Encoder找不到jar包的解决方法? 在MyEclipse中编写Java代码时,用到了BASE64Decoder,import sun.misc.BASE64Decoder;可是Eclipse提示:  Access restriction: The type BASE64Decoder is not ...

    sun.misc.BASE64Decoder.jar最新

    sun.misc.BASE64Decoder.jar sun.misc.BASE64Decoder.jar sun.misc.BASE64Decoder.jar sun.misc.BASE64Decoder.jar

    java开发 sun.misc.BASE64Decoder.jar包下载

    java开发 sun.misc.BASE64Decoder.jar包下载 java开发 sun.misc.BASE64Decoder.jar包下载

    sun.misc.jar

    Base64算法的加密解密都是使用sun.misc包下的BASE64Encoder及BASE64Decoder来进行的,例如Base64 和 Base64URL等需要依赖它

    sun.misc.BASE64Decoder.rar

    Intellij-解决报错:import sun.misc.BASE64Decoder无法找到 报错原因:JDK从1.8升级到9.0.1后sun.misc.BASE64Decoder和sun.misc.BASE64Encoder不可用 sun.misc.BASE64Decoder

    解决sun.misc.URLClassPath自动Debug缘故

    ### 解决sun.misc.URLClassPath自动Debug的问题 #### 背景介绍 在进行Java项目的开发过程中,尤其是使用集成开发环境(IDE)如Eclipse时,开发者可能会遇到一个较为罕见但又令人困惑的问题:在调试模式下启动项目时...

    sun.misc.BASE64Decoder

    在Java编程语言中,`sun.misc.BASE64Decoder`是一个内置的类,它主要用于将Base64编码的数据解码为原始字节。Base64是一种常见的数据编码方式,尤其在网络传输或者存储二进制数据时,因为许多文本格式(如JSON、XML...

    sun.misc.BASE64Decoder.jar

    如名,就是java 的sun.misc.BASE64Decoder.jar 包。 其实是已经过时的东西,因为java8推出了新的库来替代它,且android也有内置的base64相关的工具库。 但是,总有一些工程是要用老库的,也没办法(懒或者烦)更新...

    sun.misc.BASE64Decoder.zip

    《深入解析Java 7中的sun.misc.BASE64Decoder》 在Java编程中,`sun.misc.BASE64Decoder`是Java 7版本中一个用于解码Base64编码的数据的类。Base64是一种广泛使用的编码方式,它将任意二进制数据转换为可打印的...

    sun.misc.BASE64Encoder 找不到

    在Java编程中,`sun.misc.BASE64Encoder` 类曾是Java标准库早期版本中用于进行Base64编码的一个工具类。然而,由于这个类属于Sun Microsystems的内部实现细节,自Java 9开始,它被标记为废弃,并在后续版本中逐步...

Global site tag (gtag.js) - Google Analytics