unsafe类和varhandle类讲解

简介: 本文介绍了Java中的Unsafe类和VarHandle类,展示了Unsafe类如何通过底层操作绕过Java的安全限制直接访问内存和对象,以及VarHandle类如何在Java 9及以上版本中提供原子性和可变性访问。

Java的Unsafe类是一个非常特殊的类,它提供了一组原始、底层的操作,可以跳过Java的限制,直接操作内存和对象。这些操作可能会破坏Java的安全机制,所以Unsafe类被标记为不安全的。

Unsafe类提供了下列方法:

  1. allocateInstance(Class): 通过反射创建一个实例,不需要调用构造函数。

  2. arrayBaseOffset(Class): 获取数组第一个元素的偏移地址。

  3. arrayIndexScale(Class): 获取数组元素的增量地址。

  4. objectFieldOffset(Field): 获取对象实例字段的偏移地址。

  5. getInt(Object, long): 读取指定内存地址的int值。

  6. putInt(Object, long, int): 设置指定内存地址的int值。

  7. getLong(Object, long): 读取指定内存地址的long值。

  8. putLong(Object, long, long): 设置指定内存地址的long值。

  9. getObject(Object, long): 读取指定内存地址的对象引用。

  10. putObject(Object, long, Object): 设置指定内存地址的对象引用。

这些方法可以用于实现JVM底层的操作,比如手动管理内存、对象序列化、实现基于CAS的并发控制等。但Unsafe类也会带来非常大的安全风险,所以在使用时必须要非常谨慎。

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;
  public   String name;
}

pom依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>jdk21Test001</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.86.Final</version>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.21.9</version>
        </dependency>

        <!--  proto 与 Json 互转会用到-->
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
            <version>3.21.9</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>
    </dependencies>

  <build>
      <plugins>
          <plugin>
              <groupId>org.xolstice.maven.plugins</groupId>
              <artifactId>protobuf-maven-plugin</artifactId>
              <version>0.5.0</version>
          </plugin>
      </plugins>
  </build>
</project>

结果:

VarHandle类是Java 9中引入的一种新的方式,用于在Java中进行原子性和可变性访问。它提供了一种机制,可以在不使用锁的情况下对共享数据进行原子性访问。VarHandle类可以用于访问对象字段,数组元素和静态字段。它提供了一组方法,可以执行原子性读取,写入和更新操作。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 xHandle = MethodHandles.lookup().in(Message.class).findVarHandle(Message.class, "id", int.class);
        System.out.println(xHandle);
        int o = (int)xHandle.get(new Message());
        System.out.println(o);
    }
}

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;
}

输出结果:

搬迁:

var code = "80b25dea-91e5-4922-8239-bd19358058fb"
目录
相关文章
|
2月前
|
安全 Java
synchronized修饰普通方法和静态方法的区别
在Java多线程中,`synchronized`关键字用于同步机制,确保线程安全。修饰普通方法时,同步基于对象实例,仅同步访问同一对象的方法调用,不同对象间互不影响。修饰静态方法时,则基于类级别,所有对象访问同一静态方法时会互相阻塞。前者适合保护对象状态,后者适用于类级资源同步。需注意,修饰静态方法可能会影响并发性能。实际应用中应根据需求选择适当的同步策略,以平衡程序正确性和效率。
|
4月前
|
安全 NoSQL Java
探索Java Optional类:构造器、成员变量与方法
探索Java Optional类:构造器、成员变量与方法
Java-----抽象类为什么不能实例化?抽象方法为什么不能被static修饰?set和get方法的使用方法
Java-----抽象类为什么不能实例化?抽象方法为什么不能被static修饰?set和get方法的使用方法
|
5月前
|
Java
Java提供了四种访问修饰符来控制类、变量、方法和构造器的访问级别
Java提供了四种访问修饰符来控制类、变量、方法和构造器的访问级别
49 1
|
Java
Java-对对象的拷贝、抽象类和接口的区别、Object类、对象的比较方法和内部类(下)
Java-对对象的拷贝、抽象类和接口的区别、Object类、对象的比较方法和内部类(下)
55 0
|
Java 编译器
Java-对对象的拷贝、抽象类和接口的区别、Object类、对象的比较方法和内部类(上)
Java-对对象的拷贝、抽象类和接口的区别、Object类、对象的比较方法和内部类(上)
70 0
|
Java
java中静态方法为什么不能调用非静态方法或者变量
java中静态方法为什么不能调用非静态方法或者变量
89 0
|
存储 Java
java中final修饰符,修饰变量、方法、类的详细用法
java中final修饰符,修饰变量、方法、类的详细用法
123 0
|
Java 编译器
第19篇:Java 中的 final 关键字、嵌套类、内部类、静态嵌套类、局部类
📝 有效 final:虽然没有被final修饰,但只进行了一次赋值(若被赋值了不止一次,则不是有效 final) 📝 从 Java8 开始,如果局部变量没有被第二次赋值,则该局部变量会被认定为是【有效 final】
126 0
第19篇:Java 中的 final 关键字、嵌套类、内部类、静态嵌套类、局部类
|
存储 设计模式 Java
第18篇:Java的类变量、类方法;static 关键字;静态导入;初始化块;静态初始化块;单例模式
☘️ 被static修饰的成员变量可叫做:类变量、静态变量、静态字段 ☘️ 类变量在程序运行过程中只占用一份固定的内存(存储在方法区) ☘️ 可通过类名访问 ☘️ 可通过引用变量名访问(不推荐)
99 0
第18篇:Java的类变量、类方法;static 关键字;静态导入;初始化块;静态初始化块;单例模式