unsafe类和varhandle类讲解

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

Unsafe类提供了下列方法:

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

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

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

  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"

posted @ 2023-12-06 15:06  过移  阅读(136)  评论(0编辑  收藏  举报  来源