一:Unsafe概念了解
Unsafe类来自sun.misc包,不属于Java标准。源码类使用了大量的public static final和native方法
Java无法直接访问底层操作系统,而是通过本地(native)方法来访问。不过尽管如此,JVM还是开了一个后门,JDK中有一个类Unsafe,它提供了硬件级别的原子操作。
不能直接进行类的实例化,但是jdk源码之间可以互相实例,unsafe的实例化需要源码授信。
Unsafe在一些开源架构,中间件,系统和程序底层封装大量使用,对Java语言底层操作能力性能方面起了很大的提升。
二:unsafe类的作用
获取某个属性在内存中的位置,比如说修改对象的字段值,即使它是私有的。
获取内存地址偏移量
获取元素的偏移地址,增量地址
还能分配内存,扩充内存,释放内存
示例:
public native long staticFieldOffset(Field paramField);// 内存地址偏移量
public native int arrayBaseOffset(Class paramClass);//偏移地址
public native int arrayIndexScale(Class paramClass);//增量地址
public native long allocateMemory(long paramLong);//分配内存
public native long reallocateMemory(long paramLong1, long paramLong2);//扩充内存
public native void freeMemory(long paramLong);//释放内存

AtomicInteger 等Atomic原子操作底层还是使用unsafe 完成。

源码类
private static final Unsafe theUnsafe;
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException(“Unsafe”);
} else {
return theUnsafe;
}
}

其实VM类方法调用
public static boolean isSystemDomainLoader(ClassLoader var0) {
return var0 == null;
}

java 文件偏移量写入 java内存偏移量_偏移量

1、通过Unsafe类可以分配内存,可以释放内存;

类中提供的3个本地方法allocateMemory、reallocateMemory、freeMemory分别用于分配内存,扩充内存和释放内存,与C语言中的3个方法对应。

public native long allocateMemory(long l);
public native long reallocateMemory(long l, long l1);
public native void freeMemory(long l);

2、可以定位对象某字段的内存位置,也可以修改对象的字段值,即使它是私有的;

JAVA中对象的字段的定位可能通过staticFieldOffset方法实现,该方法返回给定field的内存地址偏移量,这个值对于给定的filed是唯一的且是固定不变的。

public native long staticFieldOffset(Field field);

3、挂起与恢复

将一个线程进行挂起是通过park方法实现的,调用 park后,线程将一直阻塞直到超时或者中断等条件出现。unpark可以终止一个挂起的线程,使其恢复正常。整个并发框架中对线程的挂起操作被封装在 LockSupport类中,LockSupport类中有各种版本pack方法,但最终都调用了Unsafe.park()方法。

public native void unpark(Object var1);
public native void park(boolean var1, long var2);

4、CAS操作 compareAndSwap**** 原子操作

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

5 细节源码
//下面是sun.misc.Unsafe.java类源码 package sun.misc;
import java.lang.reflect.Field;

public class Unsafe
{
// Singleton class.

private static Unsafe unsafe = new Unsafe();

  • 使用私有默认构造器防止创建多个实例

private Unsafe(){}

  • 获取Unsafe的单例,这个方法调用应该防止在不可信的代码中实例,
  • 因为unsafe类提供了一个低级别的操作,例如直接内存存取。

如果安全管理器不存在或者禁止访问系统属性

**public static Unsafe getUnsafe()

{
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPropertiesAccess();
return unsafe;
}**

  • 返回指定静态field的内存地址偏移量,在这个类的其他方法中这个值只是被用作一个访问
  • 特定field的一个方式。这个值对于 给定的field是唯一的,并且后续对该方法的调用都应该
  • 返回相同的值。

需要返回偏移量的field
指定field的偏移量

public native long objectFieldOffset(Field field);

  • 在obj的offset位置比较integer field和期望的值,如果相同则更新。这个方法
  • 的操作应该是原子的,因此提供了一种不可中断的方式更新integer field。

包含要修改field的对象
<code>obj</code>中整型field的偏移量
希望field中存在的值
如果期望值expect与field的当前值相同,设置filed的值为这个新值
如果field的值被更改

public native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);

  • 在obj的offset位置比较long field和期望的值,如果相同则更新。这个方法
  • 的操作应该是原子的,因此提供了一种不可中断的方式更新long field。

包含要修改field的对象
<code>obj</code>中long型field的偏移量
希望field中存在的值
如果期望值expect与field的当前值相同,设置filed的值为这个新值
如果field的值被更改

public native boolean compareAndSwapLong(Object obj, long offset, long expect, long update);

  • 在obj的offset位置比较object field和期望的值,如果相同则更新。这个方法
  • 的操作应该是原子的,因此提供了一种不可中断的方式更新object field。
  • 包含要修改field的对象
    .
<code>obj</code>中object型field的偏移量
  • @param expect the expected value of the field.
希望field中存在的值
如果期望值expect与field的当前值相同,设置filed的值为这个新值
如果field的值被更改

public native boolean compareAndSwapObject(Object obj, long offset, Object expect, Object update);

  • 设置obj对象中offset偏移地址对应的整型field的值为指定值。这是一个有序或者
  • 有延迟的putIntVolatile方法,并且不保证值的改变被其他线程立
  • 即看到。只有在field被volatile修饰并且期望被意外修改的时候
  • 使用才有用。

  • 包含需要修改field的对象
<code>obj</code>中整型field的偏移量
field将被设置的新值

public native void putOrderedInt(Object obj, long offset, int value);

  • 设置obj对象中offset偏移地址对应的long型field的值为指定值。这是一个有序或者
  • 有延迟的putLongVolatile方法,并且不保证值的改变被其他线程立
  • 即看到。只有在field被volatile修饰并且期望被意外修改的时候
  • 使用才有用。

  • 包含需要修改field的对象
<code>obj</code>中long型field的偏移量
field将被设置的新值

public native void putOrderedLong(Object obj, long offset, long value);

  • 设置obj对象中offset偏移地址对应的object型field的值为指定值。这是一个有序或者
  • 有延迟的putObjectVolatile方法,并且不保证值的改变被其他线程立
  • 即看到。只有在field被volatile修饰并且期望被意外修改的时候
  • 使用才有用。
  • 包含需要修改field的对象
<code>obj</code>中long型field的偏移量
field将被设置的新值

public native void putOrderedObject(Object obj, long offset, Object value);

  • 设置obj对象中offset偏移地址对应的整型field的值为指定值。支持volatile store语义
  • 包含需要修改field的对象
<code>obj</code>中整型field的偏移量
field将被设置的新值

public native void putIntVolatile(Object obj, long offset, int value);

  • 获取obj对象中offset偏移地址对应的整型field的值,支持volatile load语义。
  • 包含需要去读取的field的对象
<code>obj</code>中整型field的偏移量

public native int getIntVolatile(Object obj, long offset);

  • 设置obj对象中offset偏移地址对应的long型field的值为指定值。支持volatile store语义

包含需要修改field的对象
code>obj中long型field的偏移量

field将被设置的新值

public native void putLongVolatile(Object obj, long offset, long value);

设置obj对象中offset偏移地址对应的long型field的值为指定值。
包含需要修改field的对象
obj中long型field的偏移量
field将被设置的新值

public native void putLong(Object obj, long offset, long value);

获取obj对象中offset偏移地址对应的long型field的值,支持volatile load语义。
包含需要去读取的field的对象
obj中long型field的偏移量

public native long getLongVolatile(Object obj, long offset);

获取obj对象中offset偏移地址对应的long型field的值
包含需要去读取的field的对象
obj中long型field的偏移量

public native long getLong(Object obj, long offset);

设置obj对象中offset偏移地址对应的object型field的值为指定值。支持volatile store语义
包含需要修改field的对象
obj中object型field的偏移量

field将被设置的新值

public native void putObjectVolatile(Object obj, long offset, Object value);

设置obj对象中offset偏移地址对应的object型field的值为指定值。
包含需要修改field的对象
obj中object型field的偏移量

field将被设置的新值

public native void putObject(Object obj, long offset, Object value);

获取obj对象中offset偏移地址对应的object型field的值,支持volatile load语义。

包含需要去读取的field的对象
obj中object型field的偏移量

public native Object getObjectVolatile(Object obj, long offset);

获取给定数组中第一个元素的偏移地址。
为了存取数组中的元素,这个偏移地址与arrayIndexScale
方法的非0返回值一起被使用。
第一个元素地址被获取的class

数组第一个元素 的偏移地址

public native int arrayBaseOffset(Class arrayClass);

获取用户给定数组寻址的换算因子.一个合适的换算因子不能返回的时候(例如:基本类型),
返回0.这个返回值能够与arrayBaseOffset
一起使用去存取这个数组class中的元素

public native int arrayIndexScale(Class arrayClass);

释放被<a href="#park"><code>park</code></a>创建的在一个线程上的阻塞.这个
方法也可以被使用来终止一个先前调用<code>park</code>导致的阻塞.

这个操作操作时不安全的,因此线程必须保证是活的.这是java代码不是native代码。
要解除阻塞的线程

public native void unpark(Thread thread);

阻塞一个线程直到<a href="#unpark"><code>unpark</code></a>出现、线程
被中断或者timeout时间到期。如果一个<code>unpark</code>调用已经出现了,
这里只计数。timeout为0表示永不过期.当<code>isAbsolute</code>为true时,
timeout是相对于新纪元之后的毫秒。否则这个值就是超时前的纳秒数。这个方法执行时
也可能不合理地返回(没有具体原因)

如果为true timeout的值是一个相对于新纪元之后的毫秒数

可以是一个要等待的纳秒数,或者是一个相对于新纪元之后的毫秒数直到
到达这个时间点

public native void park(boolean isAbsolute, long time);

}