简单了解sun.misc.Unsafe

这里简单了解下sun.misc.Unsafe,jdk中的类很多地方都有用到它,它是许多类的实现的关键,知道这个类干嘛的,对一些源码的阅读很有帮助。
sun.misc.Unsafe算是Java留下的后门,能提供相当强大的操作,但是又不提供专业的文档。看名字就知道,sun本身就不推荐使用这个类。一般应用级的代码都不应该使用它,框架级别的,用这个的很多,比如jdk自身,一些框架netty,最常见的框架spring。

jdk9做了一些限制,不过还是可以使用这个类。


这个类本身是单例的,需要通过静态方法获取唯一实例。不过编译器、运行时都会报错。编译器的降低下错误级别就行,运行时的,根据代码

public static Unsafe getUnsafe() {
    Class caller = Reflection.getCallerClass();
    if (!VM.isSystemDomainLoader(caller.getClassLoader())) // 判断调用Unsafe的类是否是BootstrapClassLoader加载的类
        throw new SecurityException("Unsafe");
    return theUnsafe;
}

知道应该是通过类加载器限制。一般我们写的类都是由Application ClassLoader(sun.misc.Launcher$AppClassLoader)进行加载的,层级比较低,这里的SystemDomainLoader就是BootstarpClassLoader(C++写的),也就是加载rt.jar里面的类的加载器,所以java.*用就不会有事,我们用就会有事。

想要使用Unsafe有两种方式。一种是用反射,比较简单

Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe u = (Unsafe) unsafeField.get(null);
另外一种是通过虚拟机启动参数-Xbootclasspath,把你的classpath变为启动路径之一,这样就是BootstarpClassLoader加载你的类,跟java.*一个待遇了,就不会报错了。


Unsafe这个类对于大多数开发者来说,主要还是供研究学习用的,用于理解一些源码设计,自己的程序尽量不要用这个类。

要用的话:下面的1234点,如果你觉得AtomicXXX满足不了,那么可以考虑使用下,影响比较小。第5点,java.util.concurrent.locks中都提供了更好的功能,不需要用。第6点,volatile有内存屏障的功能,因此一般也不需要用。第7点,不要使用,直接内存访问有一些现成的,比如java.nio和netty,可以用这些,更好更方便。第8点,用现成的框架更好,第9点,不知道用来干嘛。


下面简单说下Unsafe提供的功能

1、偏移量相关
这部分是最基础的,下面很多方法都需要这部分的配合
     long staticFieldOffset(Field f):静态属性的偏移量,用于在对应的Class对象中读写静态属性
     long objectFieldOffset(Field f):类属性的偏移量,在对应的实例对象中读写类属性
     Object staticFieldBase(Field f):返回值就是f.getDeclaringClass()
     int arrayBaseOffset(Class arrayClass):数组第一个元素的实际地址相对于整个数组对象的地址的偏移量,在C语言中原生数组首地址就是第一个元素的地址,这里可以理解为是C结构体中包含一个数组,这个数组的第一个元素的地址相对于结构体地址的偏移量。
     int arrayIndexScale(Class arrayClass):数组中一个元素占据的内存空间,就是C语言中 *(p + 1),这个“1”代表的实际内存字节数。基本类型就是基本类型的长度;对象类型,在32位虚拟机中是4字节;64位虚拟机,开启指针压缩时是4字节,不指针压缩是8字节。
此外还有一堆常量,是关于基本类型的数组,以及java.lang.Object类型的数组的基本偏移量。对这块的偏移量不好理解,那就去复习下C语言结构体,本质上就是对结构体的理解。


2、普通读写

基本类型,以及对象类型(引用)都有这三个方法,这里拿int型说。
    int getInt(long address):读取内存地址address所表示的int型,address最好是自己通过allocateMemory申请的内存中的地址,否则会产生不可预料的结果。相当于C语言,int* p = xxx ... return *p。
    int  getInt(Object o, long offset):读取一个Java对象实例中的int型变量的值(static/static final类型不行,它们属于整个类,不属于实例)。对于Java,相当于直接使用 . 运算读取属性(不通过方法),无视访问限定符,也就是全部相当于public,可以直接读写。C语言中,相当于已知结构体一个实例的内存地址o,以及结构体中某个int型属性的偏移量offset,读取结构体中这个int型的值,*(o + offset)。
    getInt(Object o, int offset) :行为同getInt(Object o, long offset),因为内存地址使用64位时会有问题,所以被废弃了。


上面三个对应的写操作

    void  putInt(long address, int x)
    void putInt(Object o, int offset, int x)
    void putInt(Object o, long offset, int x)
特别地,这些可以用来更改final/static final属性的值


3、volatile相关的读写

能够对非volatile修饰的变量执行volatile读写。
    int getIntVolatile(Object o, long offset)
    void putIntVolatile(Object o, long offset, int x)
基本类型以及对象类型都有上面这两个方法。

volatile变量执行orderedSet/lazySet
     void putOrderedInt(Object o, long offset, int x)
volatile变量的写,能够对其他线程立即可见,还隐含地具有顺序性。这个方法的作用就是只保持顺序性,但不保证对其他立即可见,只有volatile写一半的功能。它避免了其他线程中已经读取了的本地变量,因为volatile写而失效,降低对volatile变量的写引起的巨大开销,提升程序整体效率。常用于不要求严格的读写一致性,但要求写操作准确无误的地方,比如ConcurrentHashMap。
这个方法只有int long Object 三个版本,其余的需要通过自己转化(可以在程序设计时,使用int替换boolean char short float,使用long替换double,运行时使用方法进行转换,或者直接使用基本类型的包装类)。


简单看几个例子,学习下如何使用Unsafe提供的底层读写功能。

// 属性读写,可以绕过访问限制
public class TestUnsafe {
    public static void main(String[] args) {
        try {
            Field unsafeField = Unsafe.class.getDeclaredFields()[0];
            unsafeField.setAccessible(true);
            Unsafe u = (Unsafe) unsafeField.get(null);
            Class tk = A.class;
            A a = new A();

            // 下面这些偏移量实际都可以用常量来表示,在一次程序运行过程中它们是不变的
            long offset = u.objectFieldOffset(tk.getDeclaredField("x"));
            System.err.println(u.getInt(a, offset)); // 读取x

            long finalOffset = u.objectFieldOffset(tk.getDeclaredField("finalX"));
            System.err.println(u.getInt(a, finalOffset)); // 读取finalX 233
            u.putInt(a, finalOffset, 100); // 可以用来更改final的值
            System.err.println(u.getInt(a, finalOffset)); // 读取finalX 100

            Object staticBase = u.staticFieldBase(tk.getDeclaredField("staticX")); // 这里就是返回 A.class,跟逻辑是一致
            long staticOffset = u.staticFieldOffset(tk.getDeclaredField("staticX"));
            System.err.println(u.getInt(staticBase, staticOffset));

            long staticFinalOffset = u.staticFieldOffset(tk.getDeclaredField("staticFinalX"));
            System.err.println(u.getInt(staticBase, staticFinalOffset));

            System.err.println(A.class == staticBase); // true
            System.err.println(u.getInt(A.class, staticOffset)); // 等价于u.getInt(staticBase, staticOffset)
        } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

class A {
    private int x = 123456;
    private final int finalX = 233;
    private static int staticX = 987654;
    private static final int staticFinalX = 666;
}

// Unsafe提供的强化数组读写的功能
// 大多数情况都可以直接使用AtomicReferenceArray来代替
public class TestArrayOffset {
    static Unsafe U;
    static {
        try {
            Field unsafeField = Unsafe.class.getDeclaredFields()[0];
            unsafeField.setAccessible(true);
            U = (Unsafe) unsafeField.get(null);
        } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    // 这个可以认为就是求a[i],不过这种看不出有什么实际的价值
    // getIntVolatile/putIntVolatile就很有价值了,提供了数组元素的volatile读写,如果写入的值不依赖当前值,可以做到原子读写
    // AtomicReferenceArray就是这样实现数组中某个元素的原子读写
    static int array(Object a, int i) {
        return U.getInt(a, (long)(Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * i));
    }

    public static void main(String[] args) {
        int[] ints = {13, 17, 19, 23, 29, 31, 37};
        for (int i = 0; i < ints.length; i++) {
            System.err.println(array(ints, i));
        }
    }
}


4、CAS相关

CAS是一些CPU直接支持的指令,是许多无锁操作的核心,是并发相关的重要知识。简单来说,它执行的操作是:如果变量在当前时刻的值和预期值expected相等,那么就 尝试把它更新为指定的值x,更新成功返回true,更新失败返回false。
    boolean compareAndSwapInt(Object o, long offset, int expected, int x)
    boolean compareAndSwapObject(Object o, long offset, Object expected, Object x)
    boolean compareAndSwapLong(Object o, long offset, long expected, long x)
只支持三个版本的,其他的需要自己转换。
CAS是个强大的操作,不过处理不了ABA的问题,这个一定要注意。另外,线程竞争很激烈时,CAS会白白浪费很多CPU时间,吞吐量反而没加锁好。
Unsafe还提供了几个对CAS简单封装的方法,用于实现AtomicXXX,可以通过这些代码简单学习下如何使用CAS。
下面这几个方法,返回值都是旧值,不是返回更新之后的值。
public final int getAndAddInt(Object o, long offset, int delta) {
    int v;
    do {
        v = getIntVolatile(o, offset);
    } while (!compareAndSwapInt(o, offset, v, v + delta));
    return v;
}

public final long getAndAddLong(Object o, long offset, long delta) {
    long v;
    do {
        v = getLongVolatile(o, offset);
    } while (!compareAndSwapLong(o, offset, v, v + delta));
    return v;
}

public final int getAndSetInt(Object o, long offset, int newValue) {
    int v;
    do {
        v = getIntVolatile(o, offset);
    } while (!compareAndSwapInt(o, offset, v, newValue));
    return v;
}

public final long getAndSetLong(Object o, long offset, long newValue) {
    long v;
    do {
        v = getLongVolatile(o, offset);
    } while (!compareAndSwapLong(o, offset, v, newValue));
    return v;
}

public final Object getAndSetObject(Object o, long offset, Object newValue) {
    Object v;
    do {
        v = getObjectVolatile(o, offset);
    } while (!compareAndSwapObject(o, offset, v, newValue));
    return v;
}
虽然简单,不过要表达的意思很清楚:CAS无锁操作使用上的重点就是循环,以及配套的volatile。

5、线程调度相关
    void unpark(Object thread)
    void park(boolean isAbsolute, long time)
LockSupport中对这两个方法进行了简单的封装,这里就先不说了,后面再专门看下LockSupport。
下面三个是关于对象锁的,synchronized会使用monitor来实现,因此下面几个可以模拟synchronized的功能,try方法获取不到时会返回false,可以避免线程死等。
    void monitorEnter(Object o)
    void monitorExit(Object o)
    boolean tryMonitorEnter(Object o)


6、内存屏障

    void loadFence():运行时保证程序代码中,在该方法之前的所有读操作,一定在load屏障之前执行完成,x86有现成的指令lfence
    void storeFence():运行时保证程序代码中,在该方法之前的所有写操作,一定在store屏障之前执行完成 ,x86有现成的指令sfence
    void fullFence():运行时保证程序代码中,在该方法之前的所有读写操作,一定在full屏障之前执行完成,x86有现成的指令mfence,这个内存屏障相当于上面两个的合体功能
这块需要理解Java内存模型,本人只懂点皮毛,就不说了。


7、直接内存操作
提供C语言式的直接内存操作的相关方法,内存在DirectMemory上进行分配,同时需要自己手动释放回收
    long allocateMemory(long bytes):可以理解为C语言malloc,内存空间也是未初始化的
    long reallocateMemory(long address, long bytes):可以理解为C语言realloc,用于已经申请的内存空间的容量变化
    void setMemory(Object o, long offset, long bytes, byte value):可以理解为C语言memset,用于初始化内存
    void setMemory(long address, long bytes, byte value):等价于 setMemory(null, address, bytes, value)
    void copyMemory(Object srcBase, long srcOffset,  Object destBase, long destOffset, long bytes):可以理解为C语言memcpy,内存内容拷贝
    void copyMemory(long srcAddress, long destAddress, long bytes):等价于 copyMemory(null, srcAddress, null, destAddress, bytes)
     void freeMemory(long address):可以理解为C语言free,用于释放手动申请的内存
这块功能就很强大了,不过也最危险,所以不要直接用,用现成的框架更好。


8、类加载相关
    boolean shouldBeInitialized(Class c):判断是否需要加载一个类
    void ensureClassInitialized(Class c):确保类一定被加载
    Class defineClass(String name, byte[] b, int off, int len,  ClassLoader loader, ProtectionDomain protectionDomain):定义一个类,可以用于动态创建类
    Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches):定义一个匿名类,可以用于动态创建类
    Object allocateInstance(Class cls)  throws InstantiationException:创建对象,但是不会调用构造方法,构造方法外的普通属性(除了static/final/static)也不会被初始化,构造方法外的普通代码块也不会被执行,这对反序列化很有用。

9、其他
int pageSize():操作系统内存页大小
int getLoadAverage(double[] loadavg, int nelems):看名字像是获取系统平均负载
void throwException(Throwable ee):抛出异常,可以绕过编译器检查

下面的是Unsafe的代码,没什么逻辑,价值不大,不过还是贴下

/*
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.misc;

import java.security.*;
import java.lang.reflect.*;

import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;


/**
 * A collection of methods for performing low-level, unsafe operations.
 * Although the class and all methods are public, use of this class is
 * limited because only trusted code can obtain instances of it.
 *
 * @author John R. Rose
 * @see #getUnsafe
 */

public final class Unsafe {

    private static native void registerNatives();
    static {
        registerNatives();
        sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe");
    }

    private Unsafe() {}

    private static final Unsafe theUnsafe = new Unsafe();

    /**
     * Provides the caller with the capability of performing unsafe
     * operations.
     *
     * 

The returned Unsafe object should be carefully guarded * by the caller, since it can be used to read and write data at arbitrary * memory addresses. It must never be passed to untrusted code. * *

Most methods in this class are very low-level, and correspond to a * small number of hardware instructions (on typical machines). Compilers * are encouraged to optimize these methods accordingly. * *

Here is a suggested idiom for using unsafe operations: * *

     * class MyTrustedClass {
     *   private static final Unsafe unsafe = Unsafe.getUnsafe();
     *   ...
     *   private long myCountAddress = ...;
     *   public int getCount() { return unsafe.getByte(myCountAddress); }
     * }
     * 
* * (It may assist compilers to make the local variable be * final.) * * @exception SecurityException if a security manager exists and its * checkPropertiesAccess method doesn't allow * access to the system properties. */ @CallerSensitive public static Unsafe getUnsafe() { Class caller = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(caller.getClassLoader())) throw new SecurityException("Unsafe"); return theUnsafe; } /// peek and poke operations /// (compilers should optimize these to memory ops) // These work on object fields in the Java heap. // They will not work on elements of packed arrays. /** * Fetches a value from a given Java variable. * More specifically, fetches a field or array element within the given * object o at the given offset, or (if o is * null) from the memory address whose numerical value is the given * offset. *

* The results are undefined unless one of the following cases is true: *

    *
  • The offset was obtained from {@link #objectFieldOffset} on * the {@link java.lang.reflect.Field} of some Java field and the object * referred to by o is of a class compatible with that * field's class. * *
  • The offset and object reference o (either null or * non-null) were both obtained via {@link #staticFieldOffset} * and {@link #staticFieldBase} (respectively) from the * reflective {@link Field} representation of some Java field. * *
  • The object referred to by o is an array, and the offset * is an integer of the form B+N*S, where N is * a valid index into the array, and B and S are * the values obtained by {@link #arrayBaseOffset} and {@link * #arrayIndexScale} (respectively) from the array's class. The value * referred to is the Nth element of the array. * *
*

* If one of the above cases is true, the call references a specific Java * variable (field or array element). However, the results are undefined * if that variable is not in fact of the type returned by this method. *

* This method refers to a variable by means of two parameters, and so * it provides (in effect) a double-register addressing mode * for Java variables. When the object reference is null, this method * uses its offset as an absolute address. This is similar in operation * to methods such as {@link #getInt(long)}, which provide (in effect) a * single-register addressing mode for non-Java variables. * However, because Java variables may have a different layout in memory * from non-Java variables, programmers should not assume that these * two addressing modes are ever equivalent. Also, programmers should * remember that offsets from the double-register addressing mode cannot * be portably confused with longs used in the single-register addressing * mode. * * @param o Java heap object in which the variable resides, if any, else * null * @param offset indication of where the variable resides in a Java heap * object, if any, else a memory address locating the variable * statically * @return the value fetched from the indicated Java variable * @throws RuntimeException No defined exceptions are thrown, not even * {@link NullPointerException} */ public native int getInt(Object o, long offset); /** * Stores a value into a given Java variable. *

* The first two parameters are interpreted exactly as with * {@link #getInt(Object, long)} to refer to a specific * Java variable (field or array element). The given value * is stored into that variable. *

* The variable must be of the same type as the method * parameter x. * * @param o Java heap object in which the variable resides, if any, else * null * @param offset indication of where the variable resides in a Java heap * object, if any, else a memory address locating the variable * statically * @param x the value to store into the indicated Java variable * @throws RuntimeException No defined exceptions are thrown, not even * {@link NullPointerException} */ public native void putInt(Object o, long offset, int x); /** * Fetches a reference value from a given Java variable. * @see #getInt(Object, long) */ public native Object getObject(Object o, long offset); /** * Stores a reference value into a given Java variable. *

* Unless the reference x being stored is either null * or matches the field type, the results are undefined. * If the reference o is non-null, car marks or * other store barriers for that object (if the VM requires them) * are updated. * @see #putInt(Object, int, int) */ public native void putObject(Object o, long offset, Object x); /** @see #getInt(Object, long) */ public native boolean getBoolean(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putBoolean(Object o, long offset, boolean x); /** @see #getInt(Object, long) */ public native byte getByte(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putByte(Object o, long offset, byte x); /** @see #getInt(Object, long) */ public native short getShort(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putShort(Object o, long offset, short x); /** @see #getInt(Object, long) */ public native char getChar(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putChar(Object o, long offset, char x); /** @see #getInt(Object, long) */ public native long getLong(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putLong(Object o, long offset, long x); /** @see #getInt(Object, long) */ public native float getFloat(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putFloat(Object o, long offset, float x); /** @see #getInt(Object, long) */ public native double getDouble(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putDouble(Object o, long offset, double x); /** * This method, like all others with 32-bit offsets, was native * in a previous release but is now a wrapper which simply casts * the offset to a long value. It provides backward compatibility * with bytecodes compiled against 1.4. * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public int getInt(Object o, int offset) { return getInt(o, (long)offset); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public void putInt(Object o, int offset, int x) { putInt(o, (long)offset, x); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public Object getObject(Object o, int offset) { return getObject(o, (long)offset); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public void putObject(Object o, int offset, Object x) { putObject(o, (long)offset, x); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public boolean getBoolean(Object o, int offset) { return getBoolean(o, (long)offset); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public void putBoolean(Object o, int offset, boolean x) { putBoolean(o, (long)offset, x); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public byte getByte(Object o, int offset) { return getByte(o, (long)offset); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public void putByte(Object o, int offset, byte x) { putByte(o, (long)offset, x); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public short getShort(Object o, int offset) { return getShort(o, (long)offset); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public void putShort(Object o, int offset, short x) { putShort(o, (long)offset, x); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public char getChar(Object o, int offset) { return getChar(o, (long)offset); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public void putChar(Object o, int offset, char x) { putChar(o, (long)offset, x); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public long getLong(Object o, int offset) { return getLong(o, (long)offset); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public void putLong(Object o, int offset, long x) { putLong(o, (long)offset, x); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public float getFloat(Object o, int offset) { return getFloat(o, (long)offset); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public void putFloat(Object o, int offset, float x) { putFloat(o, (long)offset, x); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public double getDouble(Object o, int offset) { return getDouble(o, (long)offset); } /** * @deprecated As of 1.4.1, cast the 32-bit offset argument to a long. * See {@link #staticFieldOffset}. */ @Deprecated public void putDouble(Object o, int offset, double x) { putDouble(o, (long)offset, x); } // These work on values in the C heap. /** * Fetches a value from a given memory address. If the address is zero, or * does not point into a block obtained from {@link #allocateMemory}, the * results are undefined. * * @see #allocateMemory */ public native byte getByte(long address); /** * Stores a value into a given memory address. If the address is zero, or * does not point into a block obtained from {@link #allocateMemory}, the * results are undefined. * * @see #getByte(long) */ public native void putByte(long address, byte x); /** @see #getByte(long) */ public native short getShort(long address); /** @see #putByte(long, byte) */ public native void putShort(long address, short x); /** @see #getByte(long) */ public native char getChar(long address); /** @see #putByte(long, byte) */ public native void putChar(long address, char x); /** @see #getByte(long) */ public native int getInt(long address); /** @see #putByte(long, byte) */ public native void putInt(long address, int x); /** @see #getByte(long) */ public native long getLong(long address); /** @see #putByte(long, byte) */ public native void putLong(long address, long x); /** @see #getByte(long) */ public native float getFloat(long address); /** @see #putByte(long, byte) */ public native void putFloat(long address, float x); /** @see #getByte(long) */ public native double getDouble(long address); /** @see #putByte(long, byte) */ public native void putDouble(long address, double x); /** * Fetches a native pointer from a given memory address. If the address is * zero, or does not point into a block obtained from {@link * #allocateMemory}, the results are undefined. * *

If the native pointer is less than 64 bits wide, it is extended as * an unsigned number to a Java long. The pointer may be indexed by any * given byte offset, simply by adding that offset (as a simple integer) to * the long representing the pointer. The number of bytes actually read * from the target address maybe determined by consulting {@link * #addressSize}. * * @see #allocateMemory */ public native long getAddress(long address); /** * Stores a native pointer into a given memory address. If the address is * zero, or does not point into a block obtained from {@link * #allocateMemory}, the results are undefined. * *

The number of bytes actually written at the target address maybe * determined by consulting {@link #addressSize}. * * @see #getAddress(long) */ public native void putAddress(long address, long x); /// wrappers for malloc, realloc, free: /** * Allocates a new block of native memory, of the given size in bytes. The * contents of the memory are uninitialized; they will generally be * garbage. The resulting native pointer will never be zero, and will be * aligned for all value types. Dispose of this memory by calling {@link * #freeMemory}, or resize it with {@link #reallocateMemory}. * * @throws IllegalArgumentException if the size is negative or too large * for the native size_t type * * @throws OutOfMemoryError if the allocation is refused by the system * * @see #getByte(long) * @see #putByte(long, byte) */ public native long allocateMemory(long bytes); /** * Resizes a new block of native memory, to the given size in bytes. The * contents of the new block past the size of the old block are * uninitialized; they will generally be garbage. The resulting native * pointer will be zero if and only if the requested size is zero. The * resulting native pointer will be aligned for all value types. Dispose * of this memory by calling {@link #freeMemory}, or resize it with {@link * #reallocateMemory}. The address passed to this method may be null, in * which case an allocation will be performed. * * @throws IllegalArgumentException if the size is negative or too large * for the native size_t type * * @throws OutOfMemoryError if the allocation is refused by the system * * @see #allocateMemory */ public native long reallocateMemory(long address, long bytes); /** * Sets all bytes in a given block of memory to a fixed value * (usually zero). * *

This method determines a block's base address by means of two parameters, * and so it provides (in effect) a double-register addressing mode, * as discussed in {@link #getInt(Object,long)}. When the object reference is null, * the offset supplies an absolute base address. * *

The stores are in coherent (atomic) units of a size determined * by the address and length parameters. If the effective address and * length are all even modulo 8, the stores take place in 'long' units. * If the effective address and length are (resp.) even modulo 4 or 2, * the stores take place in units of 'int' or 'short'. * * @since 1.7 */ public native void setMemory(Object o, long offset, long bytes, byte value); /** * Sets all bytes in a given block of memory to a fixed value * (usually zero). This provides a single-register addressing mode, * as discussed in {@link #getInt(Object,long)}. * *

Equivalent to setMemory(null, address, bytes, value). */ public void setMemory(long address, long bytes, byte value) { setMemory(null, address, bytes, value); } /** * Sets all bytes in a given block of memory to a copy of another * block. * *

This method determines each block's base address by means of two parameters, * and so it provides (in effect) a double-register addressing mode, * as discussed in {@link #getInt(Object,long)}. When the object reference is null, * the offset supplies an absolute base address. * *

The transfers are in coherent (atomic) units of a size determined * by the address and length parameters. If the effective addresses and * length are all even modulo 8, the transfer takes place in 'long' units. * If the effective addresses and length are (resp.) even modulo 4 or 2, * the transfer takes place in units of 'int' or 'short'. * * @since 1.7 */ public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes); /** * Sets all bytes in a given block of memory to a copy of another * block. This provides a single-register addressing mode, * as discussed in {@link #getInt(Object,long)}. * * Equivalent to copyMemory(null, srcAddress, null, destAddress, bytes). */ public void copyMemory(long srcAddress, long destAddress, long bytes) { copyMemory(null, srcAddress, null, destAddress, bytes); } /** * Disposes of a block of native memory, as obtained from {@link * #allocateMemory} or {@link #reallocateMemory}. The address passed to * this method may be null, in which case no action is taken. * * @see #allocateMemory */ public native void freeMemory(long address); /// random queries /** * This constant differs from all results that will ever be returned from * {@link #staticFieldOffset}, {@link #objectFieldOffset}, * or {@link #arrayBaseOffset}. */ public static final int INVALID_FIELD_OFFSET = -1; /** * Returns the offset of a field, truncated to 32 bits. * This method is implemented as follows: *

     * public int fieldOffset(Field f) {
     *     if (Modifier.isStatic(f.getModifiers()))
     *         return (int) staticFieldOffset(f);
     *     else
     *         return (int) objectFieldOffset(f);
     * }
     * 
* @deprecated As of 1.4.1, use {@link #staticFieldOffset} for static * fields and {@link #objectFieldOffset} for non-static fields. */ @Deprecated public int fieldOffset(Field f) { if (Modifier.isStatic(f.getModifiers())) return (int) staticFieldOffset(f); else return (int) objectFieldOffset(f); } /** * Returns the base address for accessing some static field * in the given class. This method is implemented as follows: *
     * public Object staticFieldBase(Class c) {
     *     Field[] fields = c.getDeclaredFields();
     *     for (int i = 0; i < fields.length; i++) {
     *         if (Modifier.isStatic(fields[i].getModifiers())) {
     *             return staticFieldBase(fields[i]);
     *         }
     *     }
     *     return null;
     * }
     * 
* @deprecated As of 1.4.1, use {@link #staticFieldBase(Field)} * to obtain the base pertaining to a specific {@link Field}. * This method works only for JVMs which store all statics * for a given class in one place. */ @Deprecated public Object staticFieldBase(Class c) { Field[] fields = c.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { if (Modifier.isStatic(fields[i].getModifiers())) { return staticFieldBase(fields[i]); } } return null; } /** * Report the location of a given field in the storage allocation of its * class. Do not expect to perform any sort of arithmetic on this offset; * it is just a cookie which is passed to the unsafe heap memory accessors. * *

Any given field will always have the same offset and base, and no * two distinct fields of the same class will ever have the same offset * and base. * *

As of 1.4.1, offsets for fields are represented as long values, * although the Sun JVM does not use the most significant 32 bits. * However, JVM implementations which store static fields at absolute * addresses can use long offsets and null base pointers to express * the field locations in a form usable by {@link #getInt(Object,long)}. * Therefore, code which will be ported to such JVMs on 64-bit platforms * must preserve all bits of static field offsets. * @see #getInt(Object, long) */ public native long staticFieldOffset(Field f); /** * Report the location of a given static field, in conjunction with {@link * #staticFieldBase}. *

Do not expect to perform any sort of arithmetic on this offset; * it is just a cookie which is passed to the unsafe heap memory accessors. * *

Any given field will always have the same offset, and no two distinct * fields of the same class will ever have the same offset. * *

As of 1.4.1, offsets for fields are represented as long values, * although the Sun JVM does not use the most significant 32 bits. * It is hard to imagine a JVM technology which needs more than * a few bits to encode an offset within a non-array object, * However, for consistency with other methods in this class, * this method reports its result as a long value. * @see #getInt(Object, long) */ public native long objectFieldOffset(Field f); /** * Report the location of a given static field, in conjunction with {@link * #staticFieldOffset}. *

Fetch the base "Object", if any, with which static fields of the * given class can be accessed via methods like {@link #getInt(Object, * long)}. This value may be null. This value may refer to an object * which is a "cookie", not guaranteed to be a real Object, and it should * not be used in any way except as argument to the get and put routines in * this class. */ public native Object staticFieldBase(Field f); /** * Detect if the given class may need to be initialized. This is often * needed in conjunction with obtaining the static field base of a * class. * @return false only if a call to {@code ensureClassInitialized} would have no effect */ public native boolean shouldBeInitialized(Class c); /** * Ensure the given class has been initialized. This is often * needed in conjunction with obtaining the static field base of a * class. */ public native void ensureClassInitialized(Class c); /** * Report the offset of the first element in the storage allocation of a * given array class. If {@link #arrayIndexScale} returns a non-zero value * for the same class, you may use that scale factor, together with this * base offset, to form new offsets to access elements of arrays of the * given class. * * @see #getInt(Object, long) * @see #putInt(Object, long, int) */ public native int arrayBaseOffset(Class arrayClass); /** The value of {@code arrayBaseOffset(boolean[].class)} */ public static final int ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe.arrayBaseOffset(boolean[].class); /** The value of {@code arrayBaseOffset(byte[].class)} */ public static final int ARRAY_BYTE_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); /** The value of {@code arrayBaseOffset(short[].class)} */ public static final int ARRAY_SHORT_BASE_OFFSET = theUnsafe.arrayBaseOffset(short[].class); /** The value of {@code arrayBaseOffset(char[].class)} */ public static final int ARRAY_CHAR_BASE_OFFSET = theUnsafe.arrayBaseOffset(char[].class); /** The value of {@code arrayBaseOffset(int[].class)} */ public static final int ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset(int[].class); /** The value of {@code arrayBaseOffset(long[].class)} */ public static final int ARRAY_LONG_BASE_OFFSET = theUnsafe.arrayBaseOffset(long[].class); /** The value of {@code arrayBaseOffset(float[].class)} */ public static final int ARRAY_FLOAT_BASE_OFFSET = theUnsafe.arrayBaseOffset(float[].class); /** The value of {@code arrayBaseOffset(double[].class)} */ public static final int ARRAY_DOUBLE_BASE_OFFSET = theUnsafe.arrayBaseOffset(double[].class); /** The value of {@code arrayBaseOffset(Object[].class)} */ public static final int ARRAY_OBJECT_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class); /** * Report the scale factor for addressing elements in the storage * allocation of a given array class. However, arrays of "narrow" types * will generally not work properly with accessors like {@link * #getByte(Object, int)}, so the scale factor for such classes is reported * as zero. * * @see #arrayBaseOffset * @see #getInt(Object, long) * @see #putInt(Object, long, int) */ public native int arrayIndexScale(Class arrayClass); /** The value of {@code arrayIndexScale(boolean[].class)} */ public static final int ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class); /** The value of {@code arrayIndexScale(byte[].class)} */ public static final int ARRAY_BYTE_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class); /** The value of {@code arrayIndexScale(short[].class)} */ public static final int ARRAY_SHORT_INDEX_SCALE = theUnsafe.arrayIndexScale(short[].class); /** The value of {@code arrayIndexScale(char[].class)} */ public static final int ARRAY_CHAR_INDEX_SCALE = theUnsafe.arrayIndexScale(char[].class); /** The value of {@code arrayIndexScale(int[].class)} */ public static final int ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale(int[].class); /** The value of {@code arrayIndexScale(long[].class)} */ public static final int ARRAY_LONG_INDEX_SCALE = theUnsafe.arrayIndexScale(long[].class); /** The value of {@code arrayIndexScale(float[].class)} */ public static final int ARRAY_FLOAT_INDEX_SCALE = theUnsafe.arrayIndexScale(float[].class); /** The value of {@code arrayIndexScale(double[].class)} */ public static final int ARRAY_DOUBLE_INDEX_SCALE = theUnsafe.arrayIndexScale(double[].class); /** The value of {@code arrayIndexScale(Object[].class)} */ public static final int ARRAY_OBJECT_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class); /** * Report the size in bytes of a native pointer, as stored via {@link * #putAddress}. This value will be either 4 or 8. Note that the sizes of * other primitive types (as stored in native memory blocks) is determined * fully by their information content. */ public native int addressSize(); /** The value of {@code addressSize()} */ public static final int ADDRESS_SIZE = theUnsafe.addressSize(); /** * Report the size in bytes of a native memory page (whatever that is). * This value will always be a power of two. */ public native int pageSize(); /// random trusted operations from JNI: /** * Tell the VM to define a class, without security checks. By default, the * class loader and protection domain come from the caller's class. */ public native Class defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain); /** * Define a class but do not make it known to the class loader or system dictionary. *

* For each CP entry, the corresponding CP patch must either be null or have * the a format that matches its tag: *

    *
  • Integer, Long, Float, Double: the corresponding wrapper object type from java.lang *
  • Utf8: a string (must have suitable syntax if used as signature or name) *
  • Class: any java.lang.Class object *
  • String: any object (not just a java.lang.String) *
  • InterfaceMethodRef: (NYI) a method handle to invoke on that call site's arguments *
* @params hostClass context for linkage, access control, protection domain, and class loader * @params data bytes of a class file * @params cpPatches where non-null entries exist, they replace corresponding CP entries in data */ public native Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches); /** Allocate an instance but do not run any constructor. Initializes the class if it has not yet been. */ public native Object allocateInstance(Class cls) throws InstantiationException; /** Lock the object. It must get unlocked via {@link #monitorExit}. */ public native void monitorEnter(Object o); /** * Unlock the object. It must have been locked via {@link * #monitorEnter}. */ public native void monitorExit(Object o); /** * Tries to lock the object. Returns true or false to indicate * whether the lock succeeded. If it did, the object must be * unlocked via {@link #monitorExit}. */ public native boolean tryMonitorEnter(Object o); /** Throw the exception without telling the verifier. */ public native void throwException(Throwable ee); /** * Atomically update Java variable to x if it is currently * holding expected. * @return true if successful */ public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); /** * Atomically update Java variable to x if it is currently * holding expected. * @return true if successful */ public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x); /** * Atomically update Java variable to x if it is currently * holding expected. * @return true if successful */ public final native boolean compareAndSwapLong(Object o, long offset, long expected, long x); /** * Fetches a reference value from a given Java variable, with volatile * load semantics. Otherwise identical to {@link #getObject(Object, long)} */ public native Object getObjectVolatile(Object o, long offset); /** * Stores a reference value into a given Java variable, with * volatile store semantics. Otherwise identical to {@link #putObject(Object, long, Object)} */ public native void putObjectVolatile(Object o, long offset, Object x); /** Volatile version of {@link #getInt(Object, long)} */ public native int getIntVolatile(Object o, long offset); /** Volatile version of {@link #putInt(Object, long, int)} */ public native void putIntVolatile(Object o, long offset, int x); /** Volatile version of {@link #getBoolean(Object, long)} */ public native boolean getBooleanVolatile(Object o, long offset); /** Volatile version of {@link #putBoolean(Object, long, boolean)} */ public native void putBooleanVolatile(Object o, long offset, boolean x); /** Volatile version of {@link #getByte(Object, long)} */ public native byte getByteVolatile(Object o, long offset); /** Volatile version of {@link #putByte(Object, long, byte)} */ public native void putByteVolatile(Object o, long offset, byte x); /** Volatile version of {@link #getShort(Object, long)} */ public native short getShortVolatile(Object o, long offset); /** Volatile version of {@link #putShort(Object, long, short)} */ public native void putShortVolatile(Object o, long offset, short x); /** Volatile version of {@link #getChar(Object, long)} */ public native char getCharVolatile(Object o, long offset); /** Volatile version of {@link #putChar(Object, long, char)} */ public native void putCharVolatile(Object o, long offset, char x); /** Volatile version of {@link #getLong(Object, long)} */ public native long getLongVolatile(Object o, long offset); /** Volatile version of {@link #putLong(Object, long, long)} */ public native void putLongVolatile(Object o, long offset, long x); /** Volatile version of {@link #getFloat(Object, long)} */ public native float getFloatVolatile(Object o, long offset); /** Volatile version of {@link #putFloat(Object, long, float)} */ public native void putFloatVolatile(Object o, long offset, float x); /** Volatile version of {@link #getDouble(Object, long)} */ public native double getDoubleVolatile(Object o, long offset); /** Volatile version of {@link #putDouble(Object, long, double)} */ public native void putDoubleVolatile(Object o, long offset, double x); /** * Version of {@link #putObjectVolatile(Object, long, Object)} * that does not guarantee immediate visibility of the store to * other threads. This method is generally only useful if the * underlying field is a Java volatile (or if an array cell, one * that is otherwise only accessed using volatile accesses). */ public native void putOrderedObject(Object o, long offset, Object x); /** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)} */ public native void putOrderedInt(Object o, long offset, int x); /** Ordered/Lazy version of {@link #putLongVolatile(Object, long, long)} */ public native void putOrderedLong(Object o, long offset, long x); /** * Unblock the given thread blocked on park, or, if it is * not blocked, cause the subsequent call to park not to * block. Note: this operation is "unsafe" solely because the * caller must somehow ensure that the thread has not been * destroyed. Nothing special is usually required to ensure this * when called from Java (in which there will ordinarily be a live * reference to the thread) but this is not nearly-automatically * so when calling from native code. * @param thread the thread to unpark. * */ public native void unpark(Object thread); /** * Block current thread, returning when a balancing * unpark occurs, or a balancing unpark has * already occurred, or the thread is interrupted, or, if not * absolute and time is not zero, the given time nanoseconds have * elapsed, or if absolute, the given deadline in milliseconds * since Epoch has passed, or spuriously (i.e., returning for no * "reason"). Note: This operation is in the Unsafe class only * because unpark is, so it would be strange to place it * elsewhere. */ public native void park(boolean isAbsolute, long time); /** * Gets the load average in the system run queue assigned * to the available processors averaged over various periods of time. * This method retrieves the given nelem samples and * assigns to the elements of the given loadavg array. * The system imposes a maximum of 3 samples, representing * averages over the last 1, 5, and 15 minutes, respectively. * * @params loadavg an array of double of size nelems * @params nelems the number of samples to be retrieved and * must be 1 to 3. * * @return the number of samples actually retrieved; or -1 * if the load average is unobtainable. */ public native int getLoadAverage(double[] loadavg, int nelems); // The following contain CAS-based Java implementations used on // platforms not supporting native instructions /** * Atomically adds the given value to the current value of a field * or array element within the given object o * at the given offset. * * @param o object/array to update the field/element in * @param offset field/element offset * @param delta the value to add * @return the previous value * @since 1.8 */ public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); } while (!compareAndSwapInt(o, offset, v, v + delta)); return v; } /** * Atomically adds the given value to the current value of a field * or array element within the given object o * at the given offset. * * @param o object/array to update the field/element in * @param offset field/element offset * @param delta the value to add * @return the previous value * @since 1.8 */ public final long getAndAddLong(Object o, long offset, long delta) { long v; do { v = getLongVolatile(o, offset); } while (!compareAndSwapLong(o, offset, v, v + delta)); return v; } /** * Atomically exchanges the given value with the current value of * a field or array element within the given object o * at the given offset. * * @param o object/array to update the field/element in * @param offset field/element offset * @param newValue new value * @return the previous value * @since 1.8 */ public final int getAndSetInt(Object o, long offset, int newValue) { int v; do { v = getIntVolatile(o, offset); } while (!compareAndSwapInt(o, offset, v, newValue)); return v; } /** * Atomically exchanges the given value with the current value of * a field or array element within the given object o * at the given offset. * * @param o object/array to update the field/element in * @param offset field/element offset * @param newValue new value * @return the previous value * @since 1.8 */ public final long getAndSetLong(Object o, long offset, long newValue) { long v; do { v = getLongVolatile(o, offset); } while (!compareAndSwapLong(o, offset, v, newValue)); return v; } /** * Atomically exchanges the given reference value with the current * reference value of a field or array element within the given * object o at the given offset. * * @param o object/array to update the field/element in * @param offset field/element offset * @param newValue new value * @return the previous value * @since 1.8 */ public final Object getAndSetObject(Object o, long offset, Object newValue) { Object v; do { v = getObjectVolatile(o, offset); } while (!compareAndSwapObject(o, offset, v, newValue)); return v; } /** * Ensures lack of reordering of loads before the fence * with loads or stores after the fence. * @since 1.8 */ public native void loadFence(); /** * Ensures lack of reordering of stores before the fence * with loads or stores after the fence. * @since 1.8 */ public native void storeFence(); /** * Ensures lack of reordering of loads or stores before the fence * with loads or stores after the fence. * @since 1.8 */ public native void fullFence(); /** * Throws IllegalAccessError; for use by the VM. * @since 1.8 */ private static void throwIllegalAccessError() { throw new IllegalAccessError(); } }


你可能感兴趣的:(Java基础)