JAVA-Unsafe


@SuppressWarnings("restriction")
public class UnsafeTest {

	private static final Unsafe unsafe = getUnsafe();

	private static final Object obj = new AtomicInteger(10);

	private static final long offset = objectFieldOffsetTest();

	public static final Unsafe getUnsafe() {
		try {
			Field f = Unsafe.class.getDeclaredField("theUnsafe");
			f.setAccessible(true);
			return (Unsafe) f.get(null);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * allocateInstance(Class<?> var1) 实例化对象,可以实例化私有类
	 */
	public static void allocateInstanceTest() {
		try {
//			Person person = new Person();
			Person person = (Person) unsafe.allocateInstance(Person.class);
			person.setName("haha");
			System.out.println(person.getName());
		} catch (InstantiationException e) {
			e.printStackTrace();
		}
	}

	/**
	 * objectFieldOffset(Field field)
	 *      返回指定field在对象内存中的地址偏移量,在这个类的其它方法中这个值用作访问一个特定field的一种方式,
	 *     这个值对于指定的field是惟一的,每次调用都应该返回相同的值
	 *     
	 * staticFieldOffset(Field field)
	 * 和objectFieldOffset方法类似,区别在于这个方法是获得静态成员变量的偏移量
	 */
	public static long objectFieldOffsetTest() {
		try {
			return unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
		} catch (NoSuchFieldException | SecurityException e) {
			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * compareAndSwapInt(Object obj, long offset, int expect, int update)
	 * 	比较obj的offset处内存位置中的值和期望的值,如果相同则更新,此更新是不可中断的 
	 * 	obj 	需要更新的对象 
	 * 	offset 	obj中整型field的偏移量 
	 *  expect 	期望field中存在的值 
	 *  update  如果期望值expect与field的当前值相同,设置field的值为这个新值 
	 *  return  如果field的值被更改则返回true
	 * 
	 * CAS步骤: 获取obj对象中为offset的偏移量值 比较偏移量值和expect 如果相同则更新为update,否则不更新
	 * 
	 * compareAndSwapLong(Object obj, long offset, long expect, long update)
	 * 
	 * compareAndSwapObject(Object obj, long offset, Object expect, Object update)
	 */
	public static boolean compareAndSwapIntTest() {
		boolean result = unsafe.compareAndSwapInt(obj, offset, 10, 12);
		System.out.println(obj);
		System.out.println(result);
		return result;
	}

	/**
	 * getAndSetInt(Object obj, long offset, int newValue)
	 *      为指定obj的指定offset的field赋值,并返回赋值成功时的前一个值
	 * 
	 * getAndSetLong(Object obj, long offset, long newValue)
	 * 
	 * getAndSetObject(Object obj, long offset, Object newValue)
	 * 
	 * @return
	 */
	public static int getAndSetIntTest() {
		int result = unsafe.getAndSetInt(obj, offset, 12);
		System.out.println(result);
		return result;
	}

	/**
	 * getAndAddInt(Object obj, long offset, int delta)
	 *       为指定obj的指定offset的field增加delta,并返回更新成功时的前一个值
	 * 
	 * getAndAddLong(Object obj, long offset, long delta)
	 * 
	 * @return
	 */
	public static int getAndAddIntTest() {
		int result = unsafe.getAndAddInt(obj, offset, 12);
		System.out.println(obj);
		System.out.println(result);
		return result;
	}

	/**
	 * getIntVolatile(Object obj, long offset)
	 *      获取obj对象中offset偏移地址对应整型field的值,支持volatile语义
	 * 
	 * @return
	 */
	public static int getIntVolatile() {
		int result = unsafe.getIntVolatile(obj, offset);
		System.out.println(result);
		return result;
	}

	/**
	 * putIntVolatile(Object obj, long offset, int value);
	 * 为指定对象指定offset的整型field赋值,使用volatile语义,即赋值后立马更新到主内存对其它线程可见
	 */
	public static void putIntVolatile() {
		unsafe.putIntVolatile(obj, offset, 20);
		System.out.println(obj);
	}

	/**
	 * putOrderedInt(Object obj, long offset, int value);
	 * 为指定对象指定offset的整型field赋值,没有volatile语义,即赋值后不能立马更新到主内存对其它线程可见,要求field本身有volatile修饰
	 */
	public static void putOrderedIntTest() {
		unsafe.putOrderedInt(obj, offset, 20);
		System.out.println(obj);
	}

	/**
	 * arrayBaseOffset(Class arrayClass) 获取数组第一个元素的偏移地址 
	 * arrayIndexScale(Class arrayClass) 获取数组中元素的增量地址
	 */
	public static void arrayTest() {
		String[] array1 = new String[] { "abc", "efg", "hij", "kl", "mn", "xyz" };
		String[] array2 = new String[] { "abc1", "efg1", "hij1", "kl1", "mn1", "xyz1" };
		Class<?> ak = String[].class;
		int base = unsafe.arrayBaseOffset(ak);
		int scale = unsafe.arrayIndexScale(ak);
		int shift = 31 - Integer.numberOfLeadingZeros(scale);
		// 获取数组中index为2的元素内存地址
//	        long offset = (2 << shift) + base;
		long offset = 2 * scale + base;
		String ele1 = (String) unsafe.getObject(array1, offset);
		String ele2 = (String) unsafe.getObject(array2, offset);
		System.out.println(base);
		System.out.println(scale);
		System.out.println(shift);
		System.out.println(ele1);
		System.out.println(ele2);
		// 修改array1数组索引为2的元素值
		unsafe.putObject(array1, offset, "haha");
		ele1 = (String) unsafe.getObject(array1, offset);
		System.out.println(ele1);
	}

	/**
	 * park(boolean isAbsolute, long time);
	 * 若调用之前permit数量为1,则park方法直接返回,permit数量减一;反之,等待permit数量变1,线程挂起,permit数量保持不变(permit数量为0或1)
	 * isAbsolute=false 相对时间 time=ns isAbsolute=true 绝对时间(定时) time-ms
	 * a.在调用park方法之前调用了unpark或time<0,则park直接返回,不会挂起
	 * b.如果未调用则会挂起当前线程,挂起时间为time(time>0),如果time=0,则会一直挂起
	 * c.在调用park方法之后调用unpark方法或所在线程被打断(调用interrupt方法) 
	 * d.park未知原因调用出错则直接返回(一般不会出现)
	 * 
	 * unpark(Thread thread) 若调用之前permit数量为0,permit数量加一(若此前调用了park方法,则线程恢复执行);
	 * 反之,permit数量保持不变(多次调用效果等同调用一次)
	 * 
	 * 1.当前线程已经调用过unpark(多次调用unpark和调用一次的效果一样),或time<0
	 */
	public static void parkTest1() {
		Thread curThread = Thread.currentThread();
		unsafe.unpark(curThread);
		unsafe.unpark(curThread);
		unsafe.unpark(curThread);
		unsafe.park(false, 0);
//		 unsafe.park(false, -1);
		System.out.println("Success!");
	}

	/**
	 * 2.time>0,挂起时间超时
	 */
	public static void parkTest2() {
		// 相对时间 time=ns(1s=10^9ns)
//		 unsafe.park(false, 1000000000L);
		// 绝对时间 time=ms
		long time = System.currentTimeMillis() + 1000;
		unsafe.park(true, time);
		System.out.println("Success!");
	}

	/**
	 * 3.在当前线程调用unpark方法或中断
	 * 注意: 调用interrupt和unpark方法的线程和调用park方法的线程必须是同一个线程
	 */
	public static void parkTest3() {
		Thread curThread = Thread.currentThread();
		new Thread(() -> {
			try {
				Thread.sleep(3000);
				System.out.println("sleep end.");
				curThread.interrupt();
//				unsafe.unpark(curThread);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}).start();
		unsafe.park(false, 0);
		System.out.println("Success!");
	}

	public static void main(String[] args) throws Exception {
		String[] array1 = new String[] { "abc", "efg", "hij", "kl", "mn", "xyz" };
		String[] array2 = new String[] { "abc1", "efg1", "hij1", "kl1", "mn1", "xyz1" };
		Class<?> ak = String[].class;
		int base = unsafe.arrayBaseOffset(ak);
		int scale = unsafe.arrayIndexScale(ak);
		int shift = 31 - Integer.numberOfLeadingZeros(scale);
		// 获取数组中index为2的元素内存地址
//	        long offset = (2 << shift) + base;
		long offset = 3 * scale + base;
		String ele1 = (String) unsafe.getObject(array1, offset);
		String ele2 = (String) unsafe.getObject(array2, offset);
		System.out.println("base: " + base);
		System.out.println("scale: " + scale);
		System.out.println("shift: " + shift);
		System.out.println("ele1: " + ele1);
		System.out.println("ele2: " + ele2);
		// 修改array1数组索引为2的元素值
		unsafe.putObject(array1, offset, "haha");
		ele1 = (String) unsafe.getObject(array1, offset);
		System.out.println(ele1);
	}
}

class Person {
	
	private String name;
	
	public static long age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值