看啥推荐读物
专栏名称: matoujun
r d
目录
相关文章推荐
今天看啥  ›  专栏  ›  matoujun

透过源码看JNI在java多线程编程中的作用

matoujun  · 掘金  ·  · 2018-09-13 02:22

本章开始从JDK、JVM源码的角度分析java多线程内部机制。由于Java语言的跨平台特性,JVM屏蔽了OS、硬件的差异性,其中起到关键作用的就是JNI(java native interface,java本地方法调用接口)。无论java中的线程,JVM中的线程多么强大,它们都需要依赖kernel线程完成必要的工作,而在这三者的映射过程过程中,JNI同样充当了至关重要的角色。印象我们在深入JVM源码内部debug、分析线程的管理机制之前,有必要对JNI做全面的了解。

JNI

  • 功能

JNI是一种编程框架,通过该框架使得运行在JVM中的java代码能够调用本地代码,同时也允许本地代码调用java代码。这里的本地代码可以是c,c++或者assemly语言编写的平台相关的程序。JDK和JVM的实现包括了大量的依赖JNI的代码。例如下图Thread.java类中就包括了很多native方法:

  • JNI在JVM启动阶段的作用

JVM和jdk是两个不同的概念,jdk是java语言的开发包,基于java的程序必须依赖JVM运行;而JVM除了Java,可以支持任何符合字节码规范的其他语言,像scala,kotlin,Groovy等;jdk为了支持跨平台,主要采用了c语言编写launcher,jni部分;而JVM主要采用c++编写。而JNI在JVM启动阶段的作用通过下图进行说明:

  1. 使用jdk/bin/javac编译.java源文件,生成.class文件。

  2. jdk/bin/java运行包含main方法的.class文件(javac,java都是本地可执行文件),这个时候jdk会通过jni调用/hotspot/variant-server/libjvm/libjvm.dylib(该文件为debug环境下的JVM动态库,本系列文章使用openjdk9作为debug版本,具体安装说明文档,参见openjdk9u源码分析⼀:搭建环境debug)中的jni函数,创建一个JVM实例。

  3. JVM实例初始化,加载java jar包,启动JavaMain线程以及其他JVM内部线程;

  4. 到此jdk以及jdk侧的jni交出主动权,(启动JVM的main方法,位于jdk下的main.c文件中挂起),JVM及JVM侧的jni获到主动权,JVM执行字节码,并通过JNI操作java对象。完整的交互图如下:

  • JNI的Invocation API

允许任意的本地的应用程序加载JVM实例。例如JDK是使用c语言编写的launcher,在launcher的main.c主程序中,创建JVM实例就是通过invocation方法。如下图:

jni.h文件定义了所有的jni方法;JavaVM表示一个JVM实例;JNIEnv是jni环境的引用,后面它指向了JavaVM实例,这里的JNI_CreateJavaVM即为JNI的一个invocation方法,完整的invocation方法如下图:

  • JNI function:它允许本地应用操作JVM中的对象。参见jni.h文件。

  • Native方法允许Java程序访问本地应用。Java程序中的native方法在JVM的实现中有两种命名规则。一是Java_+java包名类名被_分隔_方法名。例如:java.lang.Thread中的native void registerNatives对应jdk下Thread.c的JNIEXPORT void JNICALL Java_java_lang_Thread_registerNatives(JNIEnv *env, jclass cls)。也可以通过resigerNatives注册任意的方法名。如下图所示:

我们可以通过对JVM_SetNativeThreadName的引用来找到java中的setNativeName方法在JVM中的实现类。在jvm.cpp中:

概括起来,JNI的功能有以下几个方面:

·       创建,更新,查询Java对象

·       执行java方法

·       捕获或抛出异常

·       加载类,获取类信息

·       运行时类型检查

在接下来的文章中,我们将看到这些功能在JVM的线程管理中的体现。本系列文章列表:

Java编程思想之多线程(一)

Java编程思想之多线程(二)




原文地址:访问原文地址
快照地址: 访问文章快照