Understanding sun.misc.Unsafe
Understanding sun.misc.Unsafe
徐州绥靖公署主任 发表于7个月前
Understanding sun.misc.Unsafe
  • 发表于 7个月前
  • 阅读 17
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 新注册用户 域名抢购1元起>>>   

一:定义

private static final Unsafe theUnsafe;
static {
		registerNatives();
		Reflection.registerMethodsToFilter(Unsafe.class,
				new String[] { "getUnsafe" });
		theUnsafe = new Unsafe();
		ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe.arrayBaseOffset(boolean[].class);
		ARRAY_BYTE_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
		ARRAY_SHORT_BASE_OFFSET = theUnsafe.arrayBaseOffset(short[].class);
		ARRAY_CHAR_BASE_OFFSET = theUnsafe.arrayBaseOffset(char[].class);
		ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset(int[].class);
		ARRAY_LONG_BASE_OFFSET = theUnsafe.arrayBaseOffset(long[].class);
		ARRAY_FLOAT_BASE_OFFSET = theUnsafe.arrayBaseOffset(float[].class);
		ARRAY_DOUBLE_BASE_OFFSET = theUnsafe.arrayBaseOffset(double[].class);
		ARRAY_OBJECT_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class);
		ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class);
		ARRAY_BYTE_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class);
		ARRAY_SHORT_INDEX_SCALE = theUnsafe.arrayIndexScale(short[].class);
		ARRAY_CHAR_INDEX_SCALE = theUnsafe.arrayIndexScale(char[].class);
		ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale(int[].class);
		ARRAY_LONG_INDEX_SCALE = theUnsafe.arrayIndexScale(long[].class);
		ARRAY_FLOAT_INDEX_SCALE = theUnsafe.arrayIndexScale(float[].class);
		ARRAY_DOUBLE_INDEX_SCALE = theUnsafe.arrayIndexScale(double[].class);
		ARRAY_OBJECT_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class);
		ADDRESS_SIZE = theUnsafe.addressSize();
	}

theUnsafe属性是私有属性,且构造器私有,只提供了getUnsafe()方法拿到实例。

@CallerSensitive
	public static Unsafe getUnsafe() {
		Class arg = Reflection.getCallerClass();
		if (!VM.isSystemDomainLoader(arg.getClassLoader())) {
			throw new SecurityException("Unsafe");
		} else {
			return theUnsafe;
		}
	}

Reflection.getCallerClass()返回调用栈中最外层调用类。 在 HotSpot虚拟机中中,bootstrap启动类加载器引用是null。在应用类中,不会用到这个ClassLoader。所以,isSystemDomainLoader()的参数arg.getClassLoader()如果不是null,说明调用的ClassLoader不是Bootstrap启动类加载器,对Unsafe来说是不安全的,直接返回SecurityException. 所以不能通过getUnsafe()得到Unsafe实例。

二:获得实例

有两种方法可以获得theUnsafe属性。

1.反射属性

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

2.反射构造器

Constructor<Unsafe> unsafeConstructor = Unsafe.class.getDeclaredConstructor();
unsafeConstructor.setAccessible(true);
Unsafe unsafe = unsafeConstructor.newInstance();

三:用法

3.1 不通过构造器直接实例化指定Class的实例

class ClassWithExpensiveConstructor {

		  private final int value;

		  private ClassWithExpensiveConstructor() {
		    value = doExpensiveLookup();
		  }

		  private int doExpensiveLookup() {
		    try {
		      Thread.sleep(2000);
		    } catch (InterruptedException e) {
		      e.printStackTrace();
		    }
		    return 1;
		  }

		  public int getValue() {
		    return value;
		  }
		}


ClassWithExpensiveConstructor obj=ClassWithExpensiveConstructor.class.cast(unsafe.allocateInstance(ClassWithExpensiveConstructor.class));
Assert.assertEquals(obj.getValue(),0);

3.2 本地内存分配

getXXX(Object target, long offset) - 读取对象target位置上 指定偏移量offset的值

putXXX(Object target, long offset, XXX value) - 设置对象target位置上 指定偏移量offset的值

compareAndSwapXXX(Object target, long offset, long expectedValue, long value) -读取对象target位置上 指定偏移量offset的值 如果该值为expectedValue,则设置为新值value。该操作是原子操作。


public final native boolean compareAndSwapObject(Object arg0, long arg1,
			Object arg3, Object arg4);

public final native boolean compareAndSwapInt(Object arg0, long arg1,
			int arg3, int arg4);

public final native boolean compareAndSwapLong(Object arg0, long arg1,
			long arg3, long arg5);

@Test
public void testCopy() throws Exception {
  long address = unsafe.allocateMemory(4L);
  unsafe.putInt(address, 100);
  long otherAddress = unsafe.allocateMemory(4L);
  unsafe.copyMemory(address, otherAddress, 4L);
  assertEquals(100, unsafe.getInt(otherAddress));
}
public void place(Object o, long address) throws Exception {
  Class clazz = o.getClass();
  do {
    for (Field f : clazz.getDeclaredFields()) {
      if (!Modifier.isStatic(f.getModifiers())) {
        long offset = unsafe.objectFieldOffset(f);
        if (f.getType() == long.class) {
          unsafe.putLong(address + offset, unsafe.getLong(o, offset));
        } else if (f.getType() == int.class) {
          unsafe.putInt(address + offset, unsafe.getInt(o, offset));
        } else {
          throw new UnsupportedOperationException();
        }
      }
    }
  } while ((clazz = clazz.getSuperclass()) != null);
}

public Object read(Class clazz, long address) throws Exception {
  Object instance = unsafe.allocateInstance(clazz);
  do {
    for (Field f : clazz.getDeclaredFields()) {
      if (!Modifier.isStatic(f.getModifiers())) {
        long offset = unsafe.objectFieldOffset(f);
        if (f.getType() == long.class) {
          unsafe.putLong(instance, offset, unsafe.getLong(address + offset));
        } else if (f.getType() == int.class) {
          unsafe.putLong(instance, offset, unsafe.getInt(address + offset));
        } else {
          throw new UnsupportedOperationException();
        }
      }
    }
  } while ((clazz = clazz.getSuperclass()) != null);
  return instance;
}

@Test
public void testObjectAllocation() throws Exception {
  long containerSize = sizeOf(Container.class);
  long address = unsafe.allocateMemory(containerSize);
  Container c1 = new Container(10, 1000L);
  Container c2 = new Container(5, -10L);
  place(c1, address);
  place(c2, address + containerSize);
  Container newC1 = (Container) read(Container.class, address);
  Container newC2 = (Container) read(Container.class, address + containerSize);
  assertEquals(c1, newC1);
  assertEquals(c2, newC2);
}

此外,并发编程中底层普遍使用AbstractQueuedSynchronizer类维护锁状态变量state。

   /**
     * The synchronization state.
     */
    private volatile int state;

对于state的更新,使用Unsafe直接修改内存中的值。

/**
    * Setup to support compareAndSet. We need to natively implement
    * this here: For the sake of permitting future enhancements, we
    * cannot explicitly subclass AtomicInteger, which would be
    * efficient and useful otherwise. So, as the lesser of evils, we
    * natively implement using hotspot intrinsics API. And while we
    * are at it, we do the same for other CASable fields (which could
    * otherwise be done with atomic field updaters).
    */
   private static final Unsafe unsafe = Unsafe.getUnsafe();
   private static final long stateOffset;
   private static final long headOffset;
   private static final long tailOffset;
   private static final long waitStatusOffset;
   private static final long nextOffset;

   static {
       try {
           //获得state属性在内存中offset
           stateOffset = unsafe.objectFieldOffset
               (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
           headOffset = unsafe.objectFieldOffset
               (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
           tailOffset = unsafe.objectFieldOffset
               (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
           waitStatusOffset = unsafe.objectFieldOffset
               (Node.class.getDeclaredField("waitStatus"));
           nextOffset = unsafe.objectFieldOffset
               (Node.class.getDeclaredField("next"));

       } catch (Exception ex) { throw new Error(ex); }
   }


/**
    * Atomically sets synchronization state to the given updated
    * value if the current state value equals the expected value.
    * This operation has memory semantics of a {@code volatile} read
    * and write.
    *
    * @param expect the expected value
    * @param update the new value
    * @return {@code true} if successful. False return indicates that the actual
    *         value was not equal to the expected value.
    */
   protected final boolean compareAndSetState(int expect, int update) {
       // See below for intrinsics setup to support this
       //比较并原子更新state
       return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
   }

3.3 throw Exception

public native void throwException(Throwable arg0);

@Test(expected =ResourceNotFoundException.class)
	public void test4() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		Constructor<Unsafe> unsafeConstructor = Unsafe.class.getDeclaredConstructor();
		unsafeConstructor.setAccessible(true);
		Unsafe unsafe = unsafeConstructor.newInstance();
		unsafe.throwException(new ResourceNotFoundException());
	}

3.4 native concurrency

@Test
public void testPark() throws Exception {
  final boolean[] run = new boolean[1];
  Thread thread = new Thread() {
    @Override
    public void run() {
      unsafe.park(true, 100000L);
      run[0] = true;
    }
  };
  thread.start();
  unsafe.unpark(thread);
  thread.join(100L);
  assertTrue(run[0]);
}

四:参考资料

http://www.javaworld.com/article/2952869/java-platform/understanding-sun-misc-unsafe.html

http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/

https://dzone.com/articles/understanding-sunmiscunsafe

共有 人打赏支持
粉丝 12
博文 34
码字总数 25350
×
徐州绥靖公署主任
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: