`
xiao_jiang51
  • 浏览: 34648 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

获取强悍的sun.misc.Unsafe实例

阅读更多
java.util.concurrent 包下很多类的实现用到了基于硬件的CAS算法, 不再使用synchronized关键来进行并发控制,查看相关的源码后会发现最后都指向了一个类 ,这就是SUN未开源的sun.misc.Unsafe的类,该类功能很强大,涉及到类加载机制,其实例一般情况是获取不到的。还好有个反射的机制可以变通下,因为JVM 加载rt.jar时已经加载了该类,并且初始化过。上代码

 
/*
 * Copyright 2010, the original author or authors.  All rights reserved.
 */
package com.api;

import java.lang.reflect.Field;

import org.apache.log4j.Logger;

import sun.misc.Unsafe;

/**
 * 获取{@link sun.misc.Unsafe}实例<br>
 * 从rt.jar包中反编译该类获取的信息
 * 
 * <pre>
 * 
 * package sun.misc;
 * 
 *  import java.lang.reflect.Field;
 *  import java.lang.reflect.Modifier;
 *  import java.security.ProtectionDomain;
 *  import sun.reflect.Reflection;
 * 
 *  public final class Unsafe
 *  {
 *  private static final Unsafe theUnsafe;
 *  public static final int INVALID_FIELD_OFFSET = -1;
 * 
 *  private static native void registerNatives();
 * 
 *  public static Unsafe getUnsafe()
 *  {
 *  Class localClass = Reflection.getCallerClass(2);
 *  if (localClass.getClassLoader() != null)
 *  throw new SecurityException(&quot;Unsafe&quot;);
 *  return theUnsafe;
 *  }
 * static
 *  {
 *  registerNatives();
 * 
 *  theUnsafe = new Unsafe();
 *  }
 * ..........................
 * </pre>
 * 
 * @author <a href="mailto:xiao_jiang51@163.com">xiao jiang</a>
 * @version %I%, %G%
 * @history 2010-12-23
 */
public class UnsafeSupport {
  private static Logger log = Logger.getLogger(UnsafeSupport.class);

  private static Unsafe unsafe;

  static {
    Field field;
    try {
      // 由反编译Unsafe类获得的信息
      field = Unsafe.class.getDeclaredField("theUnsafe");
      field.setAccessible(true);
      // 获取静态属性,Unsafe在启动JVM时随rt.jar装载
      unsafe = (Unsafe) field.get(null);
    } catch (Exception e) {
      log.error("Get Unsafe instance occur error", e);
    }
  }

  /**
   * 获取{@link Unsafe }
   */
  public static Unsafe getInstance() {
    return unsafe;
  }

  public static void main(String[] args) {

  }
}


搞个测试类玩玩
/*
 *  Copyright 2010, the original author or authors.  All rights reserved.
 */
package com.api;

/**
 * 分析目标
 * 
 * @author <a href="mailto:xiao_jiang51@163.com">xiao jiang</a>
 * @version %I%, %G%
 * @history 2010-12-23
 */
public class AnalyzedTarget {

  private byte byteParam;

  private char charParam;

  private short shorteParam;

  private int intParam;

  private int intParam2;

  private long longParam;

  private double doubleParam;

  private String strParam;

  private String strParam2;
  
}


运行测试案例
/*
 *Copyright 2010, the original author or authors.  All rights reserved.
 */
package com.api;

import java.lang.reflect.Field;

import org.apache.log4j.Logger;

import sun.misc.Unsafe;

/**
 * 通过反射获取rt.jar下的Unsafe类
 * 
 * @author <a href="mailto:xiao_jiang51@163.com">xiao jiang</a>
 * @version %I%, %G%
 * @history 2010-12-23
 */
public class UnsafeTest {
  private static Logger log = Logger.getLogger(UnsafeTest.class);

  public static void main(String[] args) {
    Unsafe unsafe = UnsafeSupport.getInstance();
    // 这个很牛
    // unsafe.allocateMemory(1000000000l);

    Class clazz = AnalyzedTarget.class;
    Field[] fields = clazz.getDeclaredFields();
    log.info("fieldName:fieldOffset");
    // 获取属性偏移量,可以通过这个偏移量给属性设置
    for (Field f : fields) {
      log.info(f.getName() + ":" + unsafe.objectFieldOffset(f));
    }
    // arg0, arg1, arg2, arg3 分别是目标对象实例,目标对象属性偏移量,当前预期值,要设的值
    // unsafe.compareAndSwapInt(arg0, arg1, arg2, arg3)
    AnalyzedTarget target = new AnalyzedTarget();
    // 偏移量编译后一般不会变的,intParam这个属性的偏移量
    long intParamOffset = 24;
    // 给它设置,返回true表明设置成功, 基于有名的CAS算法的方法,并发包用这个方法很多
    log.info(unsafe.compareAndSwapInt(target, intParamOffset, 0, 3));
    //比较失败
    log.info(unsafe.compareAndSwapInt(target, intParamOffset, 0, 10));
    //验证下上面是否设置成功,应该还是3,返回ture说明上面没该
    log.info(unsafe.compareAndSwapInt(target, intParamOffset, 3, 10));
  }
}


结果
2010-12-23 16:59:56:352 [INFO]  com.api.UnsafeTest.main(UnsafeTest.java:29) - fieldName:fieldOffset
2010-12-23 16:59:56:368 [INFO]  com.api.UnsafeTest.main(UnsafeTest.java:32) - byteParam:36
2010-12-23 16:59:56:368 [INFO]  com.api.UnsafeTest.main(UnsafeTest.java:32) - charParam:32
2010-12-23 16:59:56:368 [INFO]  com.api.UnsafeTest.main(UnsafeTest.java:32) - shorteParam:34
2010-12-23 16:59:56:368 [INFO]  com.api.UnsafeTest.main(UnsafeTest.java:32) - intParam:24
2010-12-23 16:59:56:368 [INFO]  com.api.UnsafeTest.main(UnsafeTest.java:32) - intParam2:28
2010-12-23 16:59:56:368 [INFO]  com.api.UnsafeTest.main(UnsafeTest.java:32) - longParam:8
2010-12-23 16:59:56:368 [INFO]  com.api.UnsafeTest.main(UnsafeTest.java:32) - doubleParam:16
2010-12-23 16:59:56:368 [INFO]  com.api.UnsafeTest.main(UnsafeTest.java:32) - strParam:40
2010-12-23 16:59:56:368 [INFO]  com.api.UnsafeTest.main(UnsafeTest.java:32) - strParam2:44
2010-12-23 16:59:56:368 [INFO]  com.api.UnsafeTest.main(UnsafeTest.java:40) - true
2010-12-23 16:59:56:368 [INFO]  com.api.UnsafeTest.main(UnsafeTest.java:42) - false
2010-12-23 16:59:56:368 [INFO]  com.api.UnsafeTest.main(UnsafeTest.java:44) - true

注:j2sdk1.4.2_09 中compareAndSwapInt没提供,貌似1.5以上才有
bea的 jrockit81sp6_142_10中有,用到了jrockit.vm包中的Memory
1
1
分享到:
评论
4 楼 龘龘龘 2016-02-24  
sesame 写道
楼主。。。。

1,开源的,这里就有。而且和类加载没关系,只是用了native的调用
http://www.oschina.net/code/explore/gcc-4.5.2/libjava/sun/misc/Unsafe.java

2,获取也不用这么费劲,参考AtomicInteger就可以了。
	// setup to use Unsafe.compareAndSwapInt for updates
	private static final Unsafe unsafe = Unsafe.getUnsafe();

GOOD
3 楼 sesame 2012-08-28  
楼主。。。。

1,开源的,这里就有。而且和类加载没关系,只是用了native的调用
http://www.oschina.net/code/explore/gcc-4.5.2/libjava/sun/misc/Unsafe.java

2,获取也不用这么费劲,参考AtomicInteger就可以了。
	// setup to use Unsafe.compareAndSwapInt for updates
	private static final Unsafe unsafe = Unsafe.getUnsafe();
2 楼 giianhui 2011-11-04  
非常好,继续研究。
1 楼 xuhang1128 2011-10-11  
楼主,在你写这篇blog的时候Unsafe应该已经开源了吧,我想openjdk里面应该有的

相关推荐

Global site tag (gtag.js) - Google Analytics