Java为什么会引入及如何使用Unsafe

Python042

Java为什么会引入及如何使用Unsafe,第1张

sun.misc.Unsafe至少从2004年Java1.4开始就存在于Java中了。在Java9中,为了提高JVM的可维护性,Unsafe和许多其他的东西一起都被作为内部使用类隐藏起来了。但是究竟是什么取代Unsafe不得而知,个人推测会有不止一样来取代它

为了研究AQS,我们先来学习下java中cas(Compare And Swap)的基础Unsafe类的使用

Unsafe产生于java无法向c那样操作底层操作系统,但一些场景又需要相关操作.所以此类提供了一些java语言对于操作系统内存层面操作的API.这显然被认为是不安全的,所以此类是不公开的,不建议被java应用直接使用.

但现实中已经有大量的java并发相关操作的框架在使用它了....据说此类在计划废弃中.

Unsafe能操作内存?这个是什么概念?都有哪些操作呢?

其实最明显的是它大量方法都是直接操作内存地址进行操作的.方法可以分为下面几类:

我们可以使用LockSupport类进行操作

a. LockSupport.park()对应Unsafe的Unsafe.park(false, 0L)------>给当前所在线程加锁,第一个参数表示true为精度型单位为纳秒,false单位毫秒,第二次参数表示等待时间

b. LockSupport.park.unpark --------->Thread thread对应Unsafe的UNSAFE.unpark(thread)方法(解锁指定线程)

如果,我们直接使用Unsafe,是这样子的:

我们还可以通过Unsafe类获取对象的属性值.因为Unsafe类是直接操作内存的,所以需要我们获得对应的属性内存地址,如下操作:

如下操作,通过unsafe类实现cas原子操作.

好了,上面就是unsafe的基本几种使用,其也是aqs框架中cas操作的基础.下面我们进行aqs相关学习.

AQS研究系列(二)--线程状态和interrupt()、interrupted()、isInterrupted等方法学习

AQS研究系列(三)--AbstractQueuedSynchronizer源码分析

在java中内存中的对象地址是可变的,所以获得的内存地址有可能会变化。要获得内存地址也只能通过Unsafe的方法来获得,如下代码示例:

package com.bijian.study

import java.lang.reflect.Field

import sun.misc.Unsafe

public class Addresser {

//实例化Unsafe 类

private static Unsafe unsafe

static {

try {

//得到field对象

Field field = Unsafe.class.getDeclaredField("theUnsafe")

//设置获取地址

field.setAccessible(true)

unsafe = (Unsafe) field.get(null)

} catch (Exception e) {

e.printStackTrace()

}

}

public static long addressOf(Object o) throws Exception {

Object[] array = new Object[] { o }

long baseOffset = unsafe.arrayBaseOffset(Object[].class)

int addressSize = unsafe.addressSize()

long objectAddress

switch (addressSize) {

case 4:

objectAddress = unsafe.getInt(array, baseOffset)

break

case 8:

objectAddress = unsafe.getLong(array, baseOffset)

break

default:

throw new Error("unsupported address size: " + addressSize)

}

return (objectAddress)

}

//打印地址的长度

public static void main(String... args) throws Exception {

Object mine = "Hi there".toCharArray()

long address = addressOf(mine)

System.out.println("Addess: " + address)

// Verify address works - should see the characters in the array in the output

printBytes(address, 27)

}

//调用此方法得到地址

public static void printBytes(long objectAddress, int num) {

//循环打印得到的地址。

for (long i = 0 i < num i++) {

int cur = unsafe.getByte(objectAddress + i)

System.out.print((char) cur)

}

System.out.println()

}

}

运行结果: