1、如何从unsafe类获取对象
private Unsafe() {
}
@CallerSensitive
public static Unsafe getUnsafe() {
Class<?> caller = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(caller.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
从中可以看出,无法直接new出来,并且getUnsafe方法也不是给我们使用的。
2、用反射的方式从unsafe类中获取对象
由于源码里面有
private static final Unsafe theUnsafe;
所以我们可以使用:
public static Unsafe reflectGetUnsafe(){
try {
Field unsafe = Unsafe.class.getDeclaredField("theUnsafe");
unsafe.setAccessible(true);
return (Unsafe) unsafe.get(null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
3、拿到了unsafe能做什么?
1、它能修改对象地址里面的元素信息
2、它可以自己开辟一段空间用来存东西
3、它提供了原子类修改方法
4、它可以绕开java的构造器来创建对象
package memory.unsafeTest;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class UnsafeTest {
public static void main(String[] args) throws InstantiationException {
Unsafe unsafe = reflectGetUnsafe();
Message message=new Message(1,"你好");
int anInt = unsafe.getInt(message, 0);
System.out.println(anInt);
long address = unsafe.allocateMemory(4); // 分配4个字节的内存空间
unsafe.putInt(address, 21); // 将值存储到该地址上
System.out.println(unsafe.getInt(address)); // 输出:21
Message demo = (Message) unsafe.allocateInstance(Message.class);
System.out.println(demo.id); // 输出:0
unsafe.freeMemory(address); // 释放内存空间
}
public static Unsafe reflectGetUnsafe(){
try {
Field unsafe = Unsafe.class.getDeclaredField("theUnsafe");
unsafe.setAccessible(true);
return (Unsafe) unsafe.get(null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
Message类:
package memory.unsafeTest;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Message {
public int id=9;
public String name;
}
输出结果:
4、那varhandle类有什么用?
因为unsafe是不安全的且只许那些编程java的人写,所以就搞了一种更安全的类,此类可以让所有人使用
具体用法:
VarHandle xHandle = MethodHandles.lookup().in(Message.class).findVarHandle(Message.class, "id", int.class);
这个方法的作用是获取Message类中名为"id"的int类型变量的VarHandle对象。VarHandle是Java 9中引入的一种新的机制,用于在不使用反射的情况下直接访问Java对象的字段和数组元素。通过VarHandle,可以实现对变量的原子性操作,而不需要使用synchronized或者Lock等同步机制。在这个例子中,通过xHandle可以直接访问Message类中的"id"变量,从而实现对该变量的原子性操作。
为什么都要提原子操作呢?因为这个类发明的初衷就是:
随着 Java 中的并发和并行编程的不断扩展,程序员 由于无法使用 Java 结构来安排,他们越来越感到沮丧 对单个类的字段进行原子或有序操作;例如 以原子方式递增字段。到目前为止,实现的唯一方法 这些效果是使用独立的(添加两个空间 间接管理的开销和其他并发问题)或在某些方面 情况,使用原子 s(经常遇到更多的开销 比操作本身),或者使用不安全的(和不可移植的和 不支持)用于 JVM 内部函数的 API。内部函数更快, 因此,它们已被广泛使用,损害了安全性和便携性。count
AtomicInteger
FieldUpdater
sun.misc.Unsafe
如果没有这个 JEP,这些问题预计会随着原子 API 而变得更糟 展开以涵盖其他访问一致性策略(与最近的 C++ 内存模型)作为 Java 内存模型修订版的一部分
参考: JEP 193:可变句柄 (openjdk.org)
5、如何使用varhandle类
package memory.varhandleTest;
import memory.unsafeTest.Message;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
public class VarHandleTest {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
// 获取VarHandle对象
VarHandle xHandle = MethodHandles.lookup().in(Message.class).findVarHandle(Message.class, "id", int.class);
System.out.println(xHandle);
// 创建Message对象
Message message = new Message();
// 获取id字段的值
int o = (int)xHandle.get(message);
// 将id字段的值设置为2
xHandle.set(message, 2);
// 再次获取id字段的值
int i = (int)xHandle.get(message);
// 打印结果
System.out.println(o);
System.out.println(i);
}
}
结果:
它里面的原子操作:
比如说getVolatile这个方法和setVolatile这个方法到底是不是原子操作,就交由你们完成了0.0
标签:java,int,Unsafe,unsafe,import,Message,varhandle,class From: https://www.cnblogs.com/nanshaws/p/17881782.html