zoukankan      html  css  js  c++  java
  • JDK中Unsafe类详解

    在openjdk8下看Unsafe源码

    浅析Java中的原子操作

    Java并发编程之LockSupport

    http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/src/share/classes/sun/misc/Unsafe.java

    http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/tip/src/share/vm/prims/unsafe.cpp

    http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/misc/Unsafe.java

    http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/tip/src/share/vm/prims/unsafe.cpp

    案例代码

    package com.dsp.unsafe;
    
    import java.io.Serializable;
    import java.lang.reflect.Field;
    import java.util.Arrays;
    import java.util.concurrent.locks.ReentrantLock;
    
    import com.alibaba.fastjson.JSON;
    import com.dsp.json.Person;
    
    import sun.misc.Unsafe;
    
    @SuppressWarnings("restriction")
    public class UnsafeDemo {
    
    	static class Test {
    		private final int x;
    
    		Test(int x) {
    			this.x = x;
    			System.out.println("Test ctor");
    		}
    
    		int getX() {
    			return x;
    		}
    
    	}
    
    	public static void main(String[] args) throws InstantiationException, NoSuchFieldException {
    		// 获得一个UnSafe实例
    		Unsafe unsafe = null;
    		try {
    			Field f = Unsafe.class.getDeclaredField("theUnsafe");
    			f.setAccessible(true);
    			unsafe = (Unsafe) f.get(null);
    		} catch (NoSuchFieldException e) {
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		}
    
    		if (unsafe != null) {
    			try {
    				// 构造一个对象,且不调用其构造函数
    				Test test = (Test) unsafe.allocateInstance(Test.class);
    				// 得到一个对象内部属性的地址
    				long x_addr = unsafe.objectFieldOffset(Test.class.getDeclaredField("x"));
    				// 直接给此属性赋值
    				unsafe.getAndSetInt(test, x_addr, 47);
    				System.out.println(test.getX());
    			} catch (InstantiationException e) {
    				e.printStackTrace();
    			} catch (NoSuchFieldException e) {
    				e.printStackTrace();
    			}
    		}
    
    		// 通过地址操作数组
    		if (unsafe != null) {
    			final int INT_BYTES = 4;
    			int[] data = new int[10];
    			System.out.println(Arrays.toString(data));
    
    			long arrayBaseOffset = unsafe.arrayBaseOffset(int[].class);
    			System.out.println("Array address is :" + arrayBaseOffset);
    			long arrayBaseOffset2 = unsafe.arrayBaseOffset(double[].class);
    			System.out.println("Array address is :" + arrayBaseOffset2);
    
    			unsafe.putInt(data, arrayBaseOffset, 47);
    			unsafe.putInt(data, arrayBaseOffset + INT_BYTES * 8, 43);
    			System.out.println(Arrays.toString(data));
    		}
    
    		// CAS
    		if (unsafe != null) {
    			Test test = (Test) unsafe.allocateInstance(Test.class);
    			long x_addr = unsafe.objectFieldOffset(Test.class.getDeclaredField("x"));
    			unsafe.getAndSetInt(test, x_addr, 47);
    			unsafe.compareAndSwapInt(test, x_addr, 47, 78);
    			System.out.println("After CAS:" + test.getX());
    		}
    
    	}
    
    	@SuppressWarnings("deprecation")
    	public static void mainB(String[] args)
    			throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
    		Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
    		theUnsafe.setAccessible(true);
    		Unsafe UNSAFE = (Unsafe) theUnsafe.get(null);
    		System.out.println(UNSAFE);
    
    		byte[] data = new byte[10];
    		System.out.println(Arrays.toString(data));
    
    		int byteArrayBaseOffset = UNSAFE.arrayBaseOffset(byte[].class);
    		System.out.println(byteArrayBaseOffset);
    
    		UNSAFE.putByte(data, byteArrayBaseOffset, (byte) 1);
    		UNSAFE.putByte(data, byteArrayBaseOffset + 5, (byte) 5);
    		System.out.println(Arrays.toString(data));
    
    		UNSAFE.setMemory(data, byteArrayBaseOffset, 1, (byte) 2);
    		UNSAFE.setMemory(data, byteArrayBaseOffset + 5, 1, (byte) 6);
    		System.out.println(Arrays.toString(data));
    	}
    
    	@SuppressWarnings({ "unused", "rawtypes" })
    	public static void mainA(String[] args)
    			throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
    		Field field = Unsafe.class.getDeclaredField("theUnsafe");
    		field.setAccessible(true);
    		Unsafe unsafe = (Unsafe) field.get(null);
    
    		long allocateMemory = unsafe.allocateMemory(1024);
    		long theUnsafeOffset = unsafe.staticFieldOffset(field);
    		System.out.println(theUnsafeOffset);
    
    		/********************************************************************************
    		 * 获取对象中某字段在内存中的偏移量
    		 */
    		// 开始使用unsafe对象,分别找到Person对象中name属性和age属性的内存地址偏移量
    		// 首先是Person类中的name属性,在内存中设定的偏移位置
    		Field field2 = Person.class.getDeclaredField("name");
    		// 一旦这个类实例化后,该属性在内存中的偏移位置
    		long offset2 = unsafe.objectFieldOffset(field2);
    		System.out.println("name offset = " + offset2);
    		/*
    		 * 然后是Person类中的age属性,在内存中设定的偏移位置
    		 */
    		Field age3 = Person.class.getDeclaredField("age");
    		long ageOffset3 = unsafe.objectFieldOffset(age3);
    		System.out.println("age offset = " + ageOffset3);
    
    		/********************************************************************************
    		 * 修改某个字段的数据
    		 */
    		/*
    		 * 修改字段数据
    		 */
    		Person person = new Person();
    		person.setName("dsp");
    		person.setAge(20);
    		/*
    		 * 获取age属性的内存地址偏移量
    		 */
    		Field ageField = Person.class.getDeclaredField("age");
    		long ageOffset = unsafe.objectFieldOffset(ageField);
    		/*
    		 * 比较并修改值 1、需要修改的对象 2、更改属性的内存偏移量 3、预期的值 4、设置的新值
    		 */
    		if (unsafe.compareAndSwapInt(person, ageOffset, 20, 26)) {
    			System.out.println("修改数据成功");
    		} else {
    			System.out.println("修改数据失败");
    		}
    		System.out.println(JSON.toJSONString(person));
    
    		int ss, ts;
    		try {
    			Class<Segment[]> sc = Segment[].class;
    			SBASE = unsafe.arrayBaseOffset(sc);
    			ss = unsafe.arrayIndexScale(sc);
    		} catch (Exception e) {
    			throw new Error(e);
    		}
    		SSHIFT = 31 - Integer.numberOfLeadingZeros(ss);
    
    		System.out.println("SBASE=" + SBASE);
    		System.out.println("ss=" + ss);
    		System.out.println("SSHIFT=" + SSHIFT);
    
    		int ARRAY_INT_BASE_OFFSET = unsafe.arrayBaseOffset(int[].class);
    		int ARRAY_INT_INDEX_SCALE = unsafe.arrayIndexScale(int[].class);
    		System.out.println("ARRAY_INT_BASE_OFFSET=" + ARRAY_INT_BASE_OFFSET);
    		System.out.println("ARRAY_INT_INDEX_SCALE=" + ARRAY_INT_INDEX_SCALE);
    	}
    
    	// Unsafe mechanics
    	private static long SBASE;
    	private static long SSHIFT;
    
    	static final class Segment<K, V> extends ReentrantLock implements Serializable {
    		/*
    		 * Segments maintain a table of entry lists that are always kept in a consistent
    		 * state, so can be read (via volatile reads of segments and tables) without
    		 * locking. This requires replicating nodes when necessary during table
    		 * resizing, so the old lists can be traversed by readers still using old
    		 * version of table.
    		 *
    		 * This class defines only mutative methods requiring locking. Except as noted,
    		 * the methods of this class perform the per-segment versions of
    		 * ConcurrentHashMap methods. (Other methods are integrated directly into
    		 * ConcurrentHashMap methods.) These mutative methods use a form of controlled
    		 * spinning on contention via methods scanAndLock and scanAndLockForPut. These
    		 * intersperse tryLocks with traversals to locate nodes. The main benefit is to
    		 * absorb cache misses (which are very common for hash tables) while obtaining
    		 * locks so that traversal is faster once acquired. We do not actually use the
    		 * found nodes since they must be re-acquired under lock anyway to ensure
    		 * sequential consistency of updates (and in any case may be undetectably
    		 * stale), but they will normally be much faster to re-locate. Also,
    		 * scanAndLockForPut speculatively creates a fresh node to use in put if no node
    		 * is found.
    		 */
    		private static final long serialVersionUID = 2249069246763182397L;
    
    		/**
    		 * The maximum number of times to tryLock in a prescan before possibly blocking
    		 * on acquire in preparation for a locked segment operation. On multiprocessors,
    		 * using a bounded number of retries maintains cache acquired while locating
    		 * nodes.
    		 */
    		static final int MAX_SCAN_RETRIES = Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
    	}
    
    }
    

    :)

  • 相关阅读:
    3.live555源码分析----延时队列
    RTP包的结构
    2.live555源码分析----服务端doEventLoop()函数分析
    1.live555源码分析----RSTPServer创建过程分析
    RTSP协议介绍 (转)
    搭建最简单的流媒体系统(服务器和客户端)
    谈一谈 MPU6050 姿态融合(转)
    Nginx的优化
    LAMP与LNMP加速与缓存优化
    Nginx在LNMP架构中的作用与虚拟主机配置
  • 原文地址:https://www.cnblogs.com/gotodsp/p/10321015.html
Copyright © 2011-2022 走看看