JNI异常处理

       在 Java 程序中使用本机方法,就以某种基本的方式破坏了 Java 安全性模型。因为 Java程序在一个受控的运行时系统(JVM)中运行,所以 Java平台设计师决定通过检查常见运行时系统错误(如数组下标、越界错误、空指针错误)来帮助程序员。从另一方面讲,由于 C 和 C++不使用此类错误检查,所以本机方法程序员必须自己处理所有错误情况,而在运行时,这些错误可以在 JVM 中被捕获。

例如,对于 Java 程序而言,通过抛出一个异常来向 JVM报告出错是常见和正确的操作。C 没有异常,因此必须使用 JNI 的异常处理函数。

JNI的异常处理函数

有两种方法用来在本机代码中抛出异常:可以调用 Throw() 函数或 ThrowNew() 函数。在调用 Throw() 之前,首先需要创建一个Throwable 类型的对象。可以通过调用 ThrowNew() 跳过这一步,因为这个函数为您创建了该对象。在下面的示例代码片段中,我们使用这两个函数抛出 IOException

 1. 
 

2. jclass cls = (*env)->FindClass(env, "java/io/IOException");

3. jmethodID mid = (*env)->GetMethodID(env, cls, "", "()V");
 

4. jthrowable e = (*env)->NewObject(env, cls, mid);


 5. 
 

6. 

 7. (*env)->Throw(env, e);


 8. ...


 9. 

10.

11. (*env)->ThrowNew(env,


12.                  (*env)->FindClass("java/io/IOException"),

13.                  "An IOException occurred!");


Throw() 和 ThrowNew() 函数并不中断本机方法中的控制流。直到本机方法返回,在JVM 中才会将异常实际抛出。在 C中,一旦碰到错误条件,不能使用 Throw() 和 ThrowNew() 函数立即退出方法,而在Java 中,这可以使用 throw 语句来退出方法。相反,需要在Throw() 和 ThrowNew() 函数之后立即使用return 语句,以便在出错点退出本机方法。

JNI的异常捕获函数

当从 C 或 C++ 调用 Java 时,也可能需要捕获异常。 许多JNI 函数都能抛出希望捕获的异常。ExceptionCheck() 函数返回 jboolean以表明是否抛出了异常,而 ExceptionOccured() 方法返回指向当前异常的 jthrowable 引用(或者返回 NULL,如果未抛出异常的话)。

如果正在捕获异常,可能要处理异常,在这种情况下需要在 JVM中清除该异常。可以使用 ExceptionClear() 函数来进行这个操作。ExceptionDescribed() 函数用来显示异常的调试消息。

本机方法中的多线程

在使用 JNI工作时,您将遇到的更高级的问题之一是在本机方法中使用多线程。即使是在不需要支持多线程的系统上运行时,Java平台也是作为多线程系统来实现的;因此您有责任确保本机函数是线程安全的。

在 Java程序中,可以通过使用 synchronized 语句实现线程安全的代码。synchronized 语句的语法使您能够获取对象上的锁。只要在 synchronized 块中,就可以执行任何数据操作,而不必担心其它线程会悄悄进入并访问您锁定的对象。

JNI使用 MonitorEnter() 和 MonitorExit() 函数提供类似的结构。对于传递到 MonitorEnter() 函数中的对象,您会得到一个用于该对象的监视器(锁),并在使用 MonitorExit() 函数释放它之前一直持有该锁。对于您锁定的对象而言,MonitorEnter() MonitorExit() 函数之间的所有代码保证是线程安全的。

本机方法中的同步

下表显示了如何在 Java、C 和 C++中同步一块代码。正如您所见,这些 C 和 C++ 函数类似于 Java代码中的 synchronized 语句。

XML error: The image is notdisplayed because the width is greater than the maximum of 580pixels. Please decrease the image width.

随本机方法一起使用 synchronized

确保本机方法同步的另一种方法是:当在 Java类中声明 native 方法时使用 synchronized 关键字。

使用 synchronized 关键字将确保任何时候从Java 程序调用 native 方法,它都将是 synchronized。尽管用 synchronized 关键字来标记线程安全的本机方法是个好想法,但通常最好总是在本机方法实现中实现同步。这样做的主要原因如下:

  • C 或 C++ 代码和 Java本机方法声明不同,因此,如果方法声明有变动(即,如果一旦除去了 synchronized 关键字),此方法可能马上不再是线程安全的了。

  • 如果有人对使用该函数的其它本机方法(或其它 C 或 C++函数)进行编码,他们可能并没有意识到该本机实现不是线程安全的。

  • 如果将函数作为普通的 C 函数在 Java程序之外使用,则它不是线程安全的。

其它同步技术

Object.wait()Object.notify() 和 Object.notifyAll() 方法也支持线程同步。因为所有Java 对象都将 Object 类作为父类,所以所有Java 对象都有这些方法。您可以象调用其它方法一样,从本机代码调用这些方法,并以 Java代码中相同的方式来使用它们,以实现线程同步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值