Java 外部函数接口:JNI, JNA, JNR

这篇博客探讨了Java在调用操作系统接口时遇到的问题,如获取进程ID(getpid)。文章详细比较了JNI、JNA和JNR三种实现方式,包括它们的性能和实现原理。JNA通过动态代理实现,JNR则利用ASM生成直接实现类,性能优于JNA。Java 9以后的getpid实现借助JNI。博客还提供了性能测试结果和相关资源链接。
摘要由CSDN通过智能技术生成
原文: http://nullwy.me/2018/01/java...
如果觉得我的文章对你有用,请随意赞赏

遇到的问题

前段时间开发的时候,遇到一个问题,就是如何用 Java 实现 chdir?网上搜索一番,发现了 JNR-POSIX 项目 [stackoverflow ]。俗话说,好记性不如烂笔头。现在将涉及到的相关知识点总结成笔记。

其实针对 Java 实现 chdir 问题,官方 20 多年前就存在对应的 bug,即 JDK-4045688 'Add chdir or equivalent notion of changing working directory'。这个 bug 在 1997.04 创建,目前的状态是 Won't Fix(不予解决),理由大致是,若实现与操作系统一样的进程级别的 chdir,将影响 JVM 上的全部线程,这样引入了可变(mutable)的全局状态,这与 Java 的安全性优先原则冲突,现在添加全局可变的进程状态,已经太迟了,对不变性(immutability)的支持才是 Java 要实现的特性。

chdir 是平台相关的操作系统接口,POSIX 下对应的 APIint chdir(const char *path);,而 Windows 下对应的 APIBOOL WINAPI SetCurrentDirectory(_In_ LPCTSTR lpPathName);,另外 Windows 下也可以使用 MSVCRT 中 APIint _chdir(const char *dirname);(MSVCRT 下内部实现其实就是调用 SetCurrentDirectory [reactos ] )。

Java 设计理念是跨平台,"write once, run anywhere"。很平台相关的 API,虽然各个平台都有自己的类似的实现,但存在会差异。除了多数常见功能,Java 并没有对全部操作系统接口提供完整支持,比如很多 POSIX API。除了 chdir,另外一个典型的例子是,在 Java 9 以前 JDK 获取进程 id 一直没有简洁的方法 [stackoverflow ],最新发布的 Java 9 中的 JEP 102(Process API Updates)才增强了进程 API。获取进程 id 可以使用以下方式 [javadoc ]:

long pid = ProcessHandle.current().pid();

相比其他语言,Pyhon 和 Ruby,对操作系统相关的接口都有更多的原生支持。Pyhon 和 Ruby 实现的相关 API 基本上都带有 POSIX 风格。比如上文提到,chdirgetpid,在 Pyhon 和 Ruby 下对应的 API 为:Pyhon 的 os 模块 os.chdir(path)os.getpid();Ruby 的 Dir 类的 [Dir.chdir( [ string] )](https://ruby-doc.org/core-2.2... 类方法和 Process 类的 Process.pid 类属性。Python 解释器的 chdir 对应源码为 posixmodule.c#L2611,Ruby 解释器的 chdir 对应源码为 dir.c#L848win32.c#L6741

JNI 实现 getpid

Java 下要想实现本地方法调用,需要通过 JNI。关于 JNI 的介绍,可以参阅“Java核心技术,卷II:高级特性,第9版2013”的“第12章 本地方法”,或者读当年 Sun 公司 JNI 设计者 Sheng Liang(梁胜)写的“Java Native Interface: Programmer's Guide and Specification”。本文只给出实现 getpid 的一个简单示例。

首先使用 Maven 创建一个简单的脚手架:

mvn archetype:generate     \
  -DgroupId=com.test       \
  -DartifactId=jni-jnr     \
  -DpackageName=com.test   \
  -DinteractiveMode=false  

com.test 包下添加 GetPidJni 类:

package com.test;

public class GetPidJni {
    public static native long getpid();

    static {
        System.loadLibrary("getpidjni");
    }

    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值