java Unsafe.java(二)
2015-04-21 10:26
288 查看
上篇取得了Unsafe 实例, 下面分析Unsafe 的方法
1. 阻塞,释放操作
public native void park(boolean isAbsolute, long time);
调用这个方法的线程阻塞直到下列情况的发生
(1).其他线程调用了unpark(this thread)
(2).被中断
(3).超时
(4). spuriously (虚假唤醒)
释放线程操作: public native void unpark(Object thread);
2. 操作内存的方法
程序输出如下: 12, 4, 12, 1, 48. arrayBaseOffset 返回在数组对象中,数组元素的起始位置, 在jvm(32位机器) 中每个对象都有一个 “对象头”, 普通对象是8个字节(用来记录对应类在方法区的地址,和加锁情况等), 数组对象是12个字节,其中多出来的4个字节用来记录数组的长度。 而arrayIndexScale() 返回的简单说就是数组元素的字节长度。两个方法中的 getByte (long) 和getByte(Object o, long) 体现了两种寻址方式, 一个是绝对地址,
一个是相对地址寻址,相对object 的地址。
3. 类加载相关
4. CAS 的操作
以public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);为例:
1. 阻塞,释放操作
public native void park(boolean isAbsolute, long time);
调用这个方法的线程阻塞直到下列情况的发生
(1).其他线程调用了unpark(this thread)
(2).被中断
(3).超时
(4). spuriously (虚假唤醒)
释放线程操作: public native void unpark(Object thread);
2. 操作内存的方法
<span style="white-space:pre"> </span>@Test public void testAllocateMemory3() { long allocateMemory = unsafe.allocateMemory(4); unsafe.putInt(allocateMemory, 0x12345678); for (int i = 0; i < 4; i++) { byte byte1 = unsafe.getByte(allocateMemory + i); String hexString = Integer.toHexString(byte1); System.out.println(hexString); } }程序输出如下: 78, 56, 34, 12(具体输出与处理器的大端小端有关), 程序先分配4个字节的内存空间, 然后在内存上写值, 最后按照字节取值。 即使是allocateMemory(1), 也是可以的
@Test public void testArray() { String[] strArray = new String[10]; int offset = unsafe.arrayBaseOffset(strArray.getClass()); int scale = unsafe.arrayIndexScale(strArray.getClass()); System.out.println(offset); System.out.println(scale); byte[] bArray = new byte[10]; bArray[0] = 48; int offset2 = unsafe.arrayBaseOffset(bArray.getClass()); int scale2 = unsafe.arrayIndexScale(bArray.getClass()); System.out.println(offset2); System.out.println(scale2); byte b = unsafe.getByte(bArray, 12); System.out.println(b); }
程序输出如下: 12, 4, 12, 1, 48. arrayBaseOffset 返回在数组对象中,数组元素的起始位置, 在jvm(32位机器) 中每个对象都有一个 “对象头”, 普通对象是8个字节(用来记录对应类在方法区的地址,和加锁情况等), 数组对象是12个字节,其中多出来的4个字节用来记录数组的长度。 而arrayIndexScale() 返回的简单说就是数组元素的字节长度。两个方法中的 getByte (long) 和getByte(Object o, long) 体现了两种寻址方式, 一个是绝对地址,
一个是相对地址寻址,相对object 的地址。
public native long staticFieldOffset(Field f); public native long objectFieldOffset(Field f);这两个方法可以得到字段相对地址
3. 类加载相关
<span style="white-space:pre"> </span>public static class ForTest{ private void f() { System.out.println("just for test!!"); } } @Test public void testDefineClass() throws Exception { URL resource = this.getClass().getClassLoader() .getResource("com/jdkstudy/juc/MyUnsafe$ForTest.class"); File classFile = new File(resource.toURI()); InputStream in = new FileInputStream(classFile); byte[] b = new byte[10000]; int length = in.read(b); byte[] right = new byte[length]; System.arraycopy(b, 0, right, 0, length); @SuppressWarnings("deprecation") Class<?> defineClass = unsafe.defineClass( "com.jdkstudy.juc.MyUnsafe$ForTest", b, 0, length); ForTest ins = (ForTest) defineClass.newInstance(); ins.f(); in.close(); }
4. CAS 的操作
以public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);为例:
public class TestUnsafeCAS { private volatile int numCAS; public static void main(String[] args) throws InterruptedException { int threadNum = 10000; final CountDownLatch cdl1 = new CountDownLatch(threadNum); final CountDownLatch cdl2 = new CountDownLatch(1); final TestUnsafeCAS instance = new TestUnsafeCAS(); for (int i = 0; i < threadNum; i++) { Thread t = new Thread(new Runnable() { @Override public void run() { try { cdl2.await(); //something() //instance.numCAS++; // use ++ without CAS for(;;) { int expect = instance.numCAS; // use CAS to update if(unsafe.compareAndSwapInt(instance, numCASOffset, expect, expect + 1)) break; } cdl1.countDown(); } catch (Exception e) { } } }); t.start(); } cdl2.countDown(); cdl1.await(); System.out.println(instance.numCAS); } private static final Unsafe unsafe = MyUnsafe.getUnsafe(); private final static long numCASOffset; static { try { numCASOffset = unsafe.objectFieldOffset(TestUnsafeCAS.class .getDeclaredField("numCAS")); } catch (Exception ex) { throw new Error(ex); } } }如果直接使用 ++ 肯定会有并发问题, 会出现numCAS <threadNum 。 但是使用CAS 操作numCAS就不会有这个问题(失败了会重试直到成功)。 AtomicInteger已经帮我们实现了这样的功能, 参看AtomicInteger 源码会发现, 其就是用volatile的int变量来保存一个值, 用cas来更新这个值。
相关文章推荐
- JAVA UnSafe & CAS & AtomicInteger
- Java sun.misc.Unsafe 和 CAS
- java中的Unsafe
- Java中unsafe操作实例总结
- 编译.java后出现:Note:checkUser.java uses unchecked or unsafe operations.Note:Recompile with -Xlint :unchecked for details.
- 编译.java后出现:Note:checkUser.java uses unchecked or unsafe operations.Note:Recompile with -Xlint :unche
- java对象的内存布局(二):利用sun.misc.Unsafe获取类字段的偏移地址和读取字段的值
- java - Unsafe is not API
- JAVA-Unsafe
- java 并发包-Unsafe
- java - Unsafe is not API
- 出现Note: Test.java uses unchecked or unsafe operations.Note: Recompile
- (error/warning)java Unsafe等改变安全性的类怎样去掉eclipse错误提示
- 出现Note: XXX.java uses unchecked or unsafe operations.
- 解析java9中的Unsafe
- java中的unSafe类
- java - Unsafe is not API
- Java中的sun.misc.Unsafe包
- 线程进阶:多任务处理(17)——Java中的锁(Unsafe基础)
- JAVA多线程系列--Unsafe和CAS,Volatile---concurrent包的基石