Unsafe使用初探

在jdk源码中,经常能够看到sun.misc.Unsafe的使用,通过Unsafe可以操作内存管理等相关操作。
1.怎么使用Unsafe?

 

public final class Unsafe{
private static final Unsafe theUnsafe;
private Unsafe(){}
public static Unsafe getUnsafe(){
     Class cc = sun.reflect.Reflection.getCallerClass(2);
       if (cc.getClassLoader() != null)
          throw new SecurityException("Unsafe");
       return theUnsafe;
}
}

 从Unsafe类中可以看出该类并不推荐让外部用户来使用,首先构造函数为私有的,外部无法通过new实例来使用该类,其次静态的getUnsafe方法的使用也有局限,类加载器必须是bootstrap时,才会返回对应实例。

 

那该怎么办?还好可以通过反射来获取Unsafe的实例,代码如下:

 

 Field field = Unsafe.class.getDeclaredField("theUnsafe");
 field.setAccessible(true);
 Unsafe unsafe = (Unsafe)field.get(null);

 2.获取到unsafe实例后,下面主要介绍常用的功能

 

(1)修改对象的属性值

      这个在开发过程中经常会用到,通常的做法是通过反射来进行设置,现在使用unsafe也可以做到这一点。具体操作用到unsafe的objectFieldOffset方法,它返回成员属性在内存中的地址相对于对象内存地址的偏移量。通过该方法可以计算一个对象在内存中的空间大小,找出Field中偏移量最大值,然后对该最大偏移值填充字节数即为对象大小。下面比较反射以及unsafe在修改对象属性值的性能

 

import sun.misc.Unsafe;

import java.lang.reflect.Field;

/**
 * Created by yuanchen.xuyc on 2016/7/8.
 * 测试反射和unsafe
 */
public class TestUnsafe {

    static Field fieldA;
    static Field fieldB;
    static long aFieldOffset;
    static long bFieldOffset;
    static Unsafe unsafe;

    static long loopSize = 50000000;
    static long preHot = 3000;
    static {

        try {
            //1.反射
            fieldA = Bean.class.getDeclaredField("a");
            fieldB = Bean.class.getDeclaredField("b");

            fieldA.setAccessible(true);
            fieldB.setAccessible(true);

            //获取unsafe实例
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe)field.get(null);

            //获取属性a,b的偏移量
            aFieldOffset = unsafe.objectFieldOffset(fieldA);
            bFieldOffset = unsafe.objectFieldOffset(fieldB);

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }
    public static void main(String args[]) throws IllegalAccessException {

        testReflection();
        testUnsafe();
        testDirect();
    }

    static class Bean{
        private int a;
        private int b;

    }


    private static void testReflection() throws IllegalAccessException {
        Bean bean = new Bean();

        //预热
        for(int i=0; i

 在x240机器上测试的结果如下:

 

反射值set耗费:2697ms

unsafe set耗费:164ms

direct set耗费:100ms

从数据上可以看出,unsafe的耗时接近于直接赋值,而反射的性能和unsafe比起来不在一个数量级上。

(2)提供了compareAndSwap,用于实现无锁计数功能

 直接上代码,比较几种计数的效率

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by yuanchen.xuyc on 2016/7/8.
 */
public class TestCouter {
    private static int threadNum = 500;
    private static int num_to_increment = 1000000;

    public static void main(String args[]) throws InterruptedException {

        ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
        MyCounter synCounter = new SyncCounter();
        MyCounter lockCounter = new LockCounter();
        MyCounter atomicCounter = new AtomicCounter();
        MyCounter unsafeCounter = new UnsafeCounter();

        long startTime = System.currentTimeMillis();
        for(int i=0;i

 

 

你可能感兴趣的:(性能,jdk)