广告
返回顶部
首页 > 资讯 > 精选 >Java Unsafe知识点有哪些
  • 944
分享到

Java Unsafe知识点有哪些

2023-06-25 14:06:34 944人浏览 安东尼
摘要

本篇内容介绍了“Java Unsafe知识点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!sun.misc.Unsafe作用:可以用来

本篇内容介绍了“Java Unsafe知识点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

sun.misc.Unsafe

作用:可以用来在任意内存地址位置处读写数据,支持一些CAS原子操作

Java最初被设计为一种安全的受控环境。尽管如此,HotSpot还是包含了一个后门sun.misc.Unsafe,提供了一些可以直接操控内存和线程的底层操作。Unsafe被jdk广泛应用于java.NIO并发包等实现中,这个不安全的类提供了一个观察HotSpot JVM内部结构并且可以对其进行修改,但是不建议在生产环境中使用

获取Unsafe实例

Unsafe对象不能直接通过new Unsafe()或调用Unsafe.getUnsafe()获取,原因如下:

  • 不能直接new Unsafe(),原因是Unsafe被设计成单例模式,构造方法是私有的;

  • 不能通过调用Unsafe.getUnsafe()获取,因为getUnsafe被设计成只能从引导类加载器(bootstrap class loader)加载

@CallerSensitivepublic static Unsafe getUnsafe() {    Class var0 = Reflection.getCallerClass();    if (!VM.isSystemDomainLoader(var0.getClassLoader())) {        throw new SecurityException("Unsafe");    } else {        return theUnsafe;    }}

获取实例

//方法一:我们可以令我们的代码“受信任”。运行程序时,使用bootclasspath选项,指定系统类路径加上你使用的一个Unsafe路径java -Xbootclasspath:/usr/jdk1.7.0/jre/lib/rt.jar:. com.mishadoff.magic.UnsafeClient// 方法二static {    try {        Field field = Unsafe.class.getDeclaredField("theUnsafe");        field.setAccessible(true);        UNSAFE = (Unsafe) field.get(null);    } catch (Exception e) {    }}

注意:忽略你的IDE。比如:eclipse显示”Access restriction…”错误,但如果你运行代码,它将正常运行。如果这个错误提示令人烦恼,可以通过以下设置来避免:

Preferences -> Java -> Compiler -> Errors/Warnings -> Deprecated and restricted api -> Forbidden reference -> Warning

重点API

  • allocateInstance(Class<?> var1)不调用构造方法生成对象

User instance = (User) UNSAFE.allocateInstance(User.class);
  • objectFieldOffset(Field var1)返回成员属性在内存中的地址相对于对象内存地址的偏移量

  • putLong,putInt,putDouble,putChar,putObject等方法,直接修改内存数据(可以越过访问权限)

package com.quancheng;import sun.misc.Unsafe;import java.lang.reflect.Field;public class CollectionApp {    private static sun.misc.Unsafe UNSAFE;    public static void main(String[] args) {        try {            User instance = (User) UNSAFE.allocateInstance(User.class);            instance.setName("luoyoub");            System.err.println("instance:" + instance);            instance.test();            Field name = instance.getClass().getDeclaredField("name");            UNSAFE.putObject(instance, UNSAFE.objectFieldOffset(name), "huanghui");            instance.test();        } catch (Exception e) {            e.printStackTrace();        }    }    static {        try {            Field field = Unsafe.class.getDeclaredField("theUnsafe");            field.setAccessible(true);            UNSAFE = (Unsafe) field.get(null);        } catch (Exception e) {        }    }}class User {    private String name;    public void setName(String name) {        this.name = name;    }    public void test() {        System.err.println("hello,world" + name);    }}
  • copyMemory:内存数据拷贝

  • freeMemory:用于释放allocateMemory和reallocateMemory申请的内存

  • compareAndSwapInt/compareAndSwapLonGCAS操作

  • getLongVolatile/putLongVolatile

使用场景

避免初始化

当你想要跳过对象初始化阶段,或绕过构造器的安全检查,或实例化一个没有任何公共构造器的类,allocateInstance方法是非常有用的,使用构造器、反射和unsafe初始化它,将得到不同的结果

public class CollectionApp {    private static sun.misc.Unsafe UNSAFE;    public static void main(String[] args) throws IllegalAccessException, InstantiationException {        A a = new A();        a.test(); // output ==> 1        A a1 = A.class.newInstance();        a1.test(); // output ==> 1        A instance = (A) UNSAFE.allocateInstance(A.class);        instance.test(); // output ==> 0    }    static {        try {            Field field = Unsafe.class.getDeclaredField("theUnsafe");            field.setAccessible(true);            UNSAFE = (Unsafe) field.get(null);        } catch (Exception e) {        }    }}class A{    private long a;    public A(){        a = 1;    }    public void test(){        System.err.println("a==>" + a);    }}

内存崩溃(Memory corruption)

Unsafe可用于绕过安全的常用技术,直接修改内存变量;实际上,反射可以实现相同的功能。但值得关注的是,我们可以修改任何对象,甚至没有这些对象的引用

Guard guard = new Guard();guard.giveAccess();   // false, no access// bypassUnsafe unsafe = getUnsafe();Field f = guard.getClass().getDeclaredField("ACCESS_ALLOWED");unsafe.putInt(guard, unsafe.objectFieldOffset(f), 42); // memory corruptionguard.giveAccess(); // true, access granted

注意:我们不必持有这个对象的引用

  • 浅拷贝(Shallow copy)

  • 动态类(Dynamic classes)

我们可以在运行时创建一个类,比如从已编译的.class文件中。将类内容读取为字节数组,并正确地传递给defineClass方法;当你必须动态创建类,而现有代码中有一些代理, 这是很有用的

private static byte[] getClassContent() throws Exception {    File f = new File("/home/mishadoff/tmp/A.class");    FileInputStream input = new FileInputStream(f);    byte[] content = new byte[(int)f.length()];    input.read(content);    input.close();    return content;}byte[] classContents = getClassContent();Class c = getUnsafe().defineClass(              null, classContents, 0, classContents.length);c.getMethod("a").invoke(c.newInstance(), null); // 1

抛出异常(Throw an Exception)

该方法抛出受检异常,但你的代码不必捕捉或重新抛出它,正如运行时异常一样

getUnsafe().throwException(new IOException());

大数组(Big Arrays)

正如你所知,Java数组大小的最大值为Integer.MAX_VALUE。使用直接内存分配,我们创建的数组大小受限于堆大小;实际上,这是堆外内存(off-heap memory)技术,在java.nio包中部分可用;

这种方式的内存分配不在堆上,且不受GC管理,所以必须小心Unsafe.freeMemory()的使用。它也不执行任何边界检查,所以任何非法访问可能会导致JVM崩溃

class SuperArray {    private final static int BYTE = 1;    private long size;    private long address;    public SuperArray(long size) {        this.size = size;        address = getUnsafe().allocateMemory(size * BYTE);    }    public void set(long i, byte value) {        getUnsafe().putByte(address + i * BYTE, value);    }    public int get(long idx) {        return getUnsafe().getByte(address + idx * BYTE);    }    public long size() {        return size;    }}long SUPER_SIZE = (long)Integer.MAX_VALUE * 2;SuperArray array = new SuperArray(SUPER_SIZE);System.out.println("Array size:" + array.size()); // 4294967294for (int i = 0; i < 100; i++) {    array.set((long)Integer.MAX_VALUE + i, (byte)3);    sum += array.get((long)Integer.MAX_VALUE + i);}System.out.println("Sum of 100 elements:" + sum);  // 300

并发(Concurrency)

几句关于Unsafe的并发性。compareAndSwap方法是原子的,并且可用来实现高性能的、无数据结构

挂起与恢复

定义:

public native void unpark(Thread jthread);  public native void park(boolean isAbsolute, long time); // isAbsolute参数是指明时间是绝对的,还是相对的

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

unpark函数为线程提供“许可(permit)”,线程调用park函数则等待“许可”。这个有点像信号量,但是这个“许可”是不能叠加的,“许可”是一次性的;比如线程B连续调用了三次unpark函数,当线程A调用park函数就使用掉这个“许可”,如果线程A再次调用park,则进入等待状态,见下例Example1

Example1:// 针对当前线程已经调用过unpark(多次调用unpark的效果和调用一次unpark的效果一样)public static void main(String[] args) throws InterruptedException {    Thread currThread = Thread.currentThread();    UNSAFE.unpark(currThread);    UNSAFE.unpark(currThread);    UNSAFE.unpark(currThread);    UNSAFE.park(false, 0);    UNSAFE.park(false, 0);    System.out.println("SUCCESS!!!");}// 恢复线程interrupt() && UNSAFE.unpark()运行结果一样public static void main(String[] args) throws InterruptedException {    Thread currThread = Thread.currentThread();    new Thread(()->{        try {            Thread.sleep(3000);            System.err.println("sub thread end");            // currThread.interrupt();            UNSAFE.unpark(currThread);        } catch (Exception e) {            e.printStackTrace();        }    }).start();    UNSAFE.park(false, 0);    System.out.println("SUCCESS!!!");}// 如果是相对时间也就是isAbsolute为false(注意这里后面的单位纳秒)到期的时候,与Thread.sleep效果相同,具体有什么区别有待深入研究//相对时间后面的参数单位是纳秒UNSAFE.park(false, 3000000000l);System.out.println("SUCCESS!!!");long time = System.currentTimeMillis()+3000;//绝对时间后面的参数单位是毫秒UNSAFE.park(true, time);System.out.println("SUCCESS!!!");

注意,unpark函数可以先于park调用。比如线程B调用unpark函数,给线程A发了一个“许可”,那么当线程A调用park时,它发现已经有“许可”了,那么它会马上再继续运行。实际上,park函数即使没有“许可”,有时也会无理由地返回,实际上在SUN Jdk中,object.wait()也有可能被假唤醒;

注意:unpark方法最好不要在调用park前对当前线程调用unpark

Unsafe API

sun.misc.Unsafe类包含105个方法。实际上,对各种实体操作有几组重要方法,其中的一些如下:Info.仅返回一些低级的内存信息addressSizepageSizeObjects.提供用于操作对象及其字段的方法allocateInstance     ##直接获取对象实例objectFieldOffsetClasses.提供用于操作类及其静态字段的方法staticFieldOffsetdefineClassdefineAnonymousClassensureClassInitializedArrays.操作数组arrayBaseOffsetarrayIndexScaleSynchronization.低级的同步原语monitorEntertryMonitorEntermonitorExitcompareAndSwapIntputOrderedIntMemory.直接内存访问方法allocateMemorycopyMemoryfreeMemorygetAddressgetIntputInt

知识点

Unsafe.park()当遇到线程终止时,会直接返回(不同于Thread.sleep,Thread.sleep遇到thread.interrupt()会抛异常)

// Thread.sleep会抛异常public static void main(String[] args) throws InterruptedException {   Thread thread =  new Thread(()->{        try {            System.err.println("sub thread start");            Thread.sleep(10000);            System.err.println("sub thread end");        } catch (InterruptedException e) {            e.printStackTrace();        }    });   thread.start();    TimeUnit.SECONDS.sleep(3);    thread.interrupt();    System.out.println("SUCCESS!!!");}output==>sub thread startSUCCESS!!!java.lang.InterruptedException: sleep interrupted    at java.lang.Thread.sleep(Native Method)    at com.quancheng.ConcurrentTest.lambda$main$0(ConcurrentTest.java:13)    at java.lang.Thread.run(Thread.java:745)Process finished with exit code 0public static void main(String[] args) throws InterruptedException {   Thread thread =  new Thread(()->{       System.err.println("sub thread start");       UNSAFE.park(false,0);       System.err.println("sub thread end");    });   thread.start();    TimeUnit.SECONDS.sleep(3);    UNSAFE.unpark(thread);    System.out.println("SUCCESS!!!");}output==>sub thread startsub thread endSUCCESS!!!Process finished with exit code 0

unpark无法恢复处于sleep中的线程,只能与park配对使用,因为unpark发放的许可只有park能监听到

public static void main(String[] args) throws InterruptedException {    Thread thread = new Thread(() -> {        try {            System.err.println("sub thread start");            TimeUnit.SECONDS.sleep(10);            System.err.println("sub thread end");        } catch (Exception e) {            e.printStackTrace();        }    });    thread.start();    TimeUnit.SECONDS.sleep(3);    UNSAFE.unpark(thread);    System.out.println("SUCCESS!!!");}

park和unpark的灵活之处

上面已经提到,unpark函数可以先于park调用,这个正是它们的灵活之处。

一个线程它有可能在别的线程unPark之前,或者之后,或者同时调用了park,那么因为park的特性,它可以不用担心自己的park的时序问题,否则,如果park必须要在unpark之前,那么给编程带来很大的麻烦!!

”考虑一下,两个线程同步,要如何处理?

在Java5里是用wait/notify/notifyAll来同步的。wait/notify机制有个很蛋疼的地方是,比如线程B要用notify通知线程A,那么线程B要确保线程A已经在wait调用上等待了,否则线程A可能永远都在等待。编程的时候就会很蛋疼。

另外,是调用notify,还是notifyAll?

notify只会唤醒一个线程,如果错误地有两个线程在同一个对象上wait等待,那么又悲剧了。为了安全起见,貌似只能调用notifyAll了“

park/unpark模型真正解耦了线程之间的同步,线程之间不再需要一个Object或者其它变量来存储状态,不再需要关心对方的状态

“Java Unsafe知识点有哪些”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: Java Unsafe知识点有哪些

本文链接: https://www.lsjlt.com/news/305490.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java Unsafe知识点有哪些
    本篇内容介绍了“Java Unsafe知识点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!sun.misc.Unsafe作用:可以用来...
    99+
    2023-06-25
  • java URL知识点有哪些
    本篇内容主要讲解“java URL知识点有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java URL知识点有哪些”吧!01、什么是 URL为了搞清楚什么是 URL,需要引入另外两个概念 ...
    99+
    2023-06-19
  • Java多态知识点有哪些
    本篇内容主要讲解“Java多态知识点有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java多态知识点有哪些”吧!将某个对象的引用视为其基类对象的引用的做法被称作“向上转型”(upcasti...
    99+
    2023-06-03
  • Java泛型知识点有哪些
    本篇内容介绍了“Java泛型知识点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! 一 什么是泛型Java 泛型(generi...
    99+
    2023-06-15
  • Java数组知识点有哪些
    这篇文章主要介绍“Java数组知识点有哪些”,在日常操作中,相信很多人在Java数组知识点有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java数组知识点有哪些”的疑惑有所帮助!接下来,请跟着小编一起来...
    99+
    2023-06-30
  • Java基础知识点有哪些
    这篇文章主要介绍“Java基础知识点有哪些”,在日常操作中,相信很多人在Java基础知识点有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java基础知识点有哪些”的疑惑有所帮助!接下来,请跟着小编一起来...
    99+
    2023-06-02
  • Java的Queue知识点有哪些
    本篇内容主要讲解“Java的Queue知识点有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java的Queue知识点有哪些”吧!Java提供了Quere,相当好用,在1.5版本中又有增强。...
    99+
    2023-06-03
  • Java NIO的知识点有哪些
    今天小编给大家分享一下Java NIO的知识点有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。No-Block 和Blo...
    99+
    2023-06-17
  • java中Supplier知识点有哪些
    小编给大家分享一下java中Supplier知识点有哪些,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!1、说明这个接口是提供者的意思,只有一个抽象的get,没有默认的方法和静态的方法,导入一个泛T,get方法,返回一个泛T...
    99+
    2023-06-14
  • java有哪些重要知识点
    本篇内容介绍了“java有哪些重要知识点”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!JDK JRE JVMJDK:Java标准开发包,它提...
    99+
    2023-06-20
  • Java栈的知识点有哪些
    这篇文章主要介绍了Java栈的知识点有哪些的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java栈的知识点有哪些文章都会有所收获,下面我们一起来看看吧。1.栈的概念栈(stack)又名堆栈,作为一种数据结构,是...
    99+
    2023-06-29
  • Java并发知识点有哪些
    本篇内容主要讲解“Java并发知识点有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java并发知识点有哪些”吧!1.并行跟并发有什么区别?从操作系统的角度来看,线程是CPU分配的最小单位。...
    99+
    2023-06-29
  • Java后端知识点有哪些
    本篇内容主要讲解“Java后端知识点有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java后端知识点有哪些”吧!基础知识数据结构基本的数据结构是非常重要的,无论接触什么编程语言,这些基本数...
    99+
    2023-06-16
  • java的Classpath知识点有哪些
    本篇内容主要讲解“java的Classpath知识点有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java的Classpath知识点有哪些”吧!java的优点就是他是一个自动支持网络功能的...
    99+
    2023-06-03
  • java的重要知识点有哪些
    本篇内容介绍了“java的重要知识点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Spring Cloud Config配置管理工具包...
    99+
    2023-06-04
  • Java对象的知识点有哪些
    这篇文章主要讲解了“Java对象的知识点有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java对象的知识点有哪些”吧!问题的复杂性直接取决于抽象的类型和质量,同一个问题,如果抽象的方法...
    99+
    2023-06-03
  • Java必会的知识点有哪些
    本篇内容主要讲解“Java必会的知识点有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java必会的知识点有哪些”吧!基础部分知识点java开发环境搭建,建议从jdk1.8开始学习,下载jd...
    99+
    2023-06-16
  • Java继承的知识点有哪些
    今天小编给大家分享一下Java继承的知识点有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。继承继承的介绍继承是java面...
    99+
    2023-06-29
  • java中的HTML知识点有哪些
    这篇文章主要介绍“java中的HTML知识点有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“java中的HTML知识点有哪些”文章能帮助大家解决问题。   1...
    99+
    2022-10-19
  • 有哪些Java的相关知识点
    这篇文章主要介绍“有哪些Java的相关知识点”,在日常操作中,相信很多人在有哪些Java的相关知识点问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”有哪些Java的相关知识点”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-16
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作