原文来自于官方安卓开发文档中使用JNI相关注意事项,但同样也适用于其他情况下的JNI相关开发:
https://developer.android.com/training/articles/perf-jni
其中比较重要的是JNI与线程,以下是我对这一部分的翻译:
JNI之线程篇
所有的线程都是由Linux内核进行规划的Linux线程(注:因为这篇文章是出自安卓开发,所以这么说). 它们通常都是产生于Managed code(关于什么是Managed code:https://en.wikipedia.org/wiki/Managed_code),比如类似于Thread.start()这样的Managed code,但是它们也可以在别的地方被创建然后再被添加到Java虚拟机(JavaVM)中 . 比如说,一个线程如果是通过pthread_create()
或者是 std::thread
来开启的话,那这个线程可以通过AttachCurrentThread()
or AttachCurrentThreadAsDaemon()
函数来添加到Java虚拟机。在这个线程被添加到Java虚拟机之前,这个线程将不会拥有JNIEnv变量并且不能使用任何JNI功能。
通常来说,使用Thread.start()来创建线程是比较好的做法。这样的话能确保你的线程有足够的栈空间,能确保你的线程在正确的线程组里面(ThreadGroup),而且能确保你使用的类加载器(ClassLoader)和你的Java代码所使用的类加载器是相同的。还没完,Java代码创建的线程相比于用本地(native)代码创建的线程能更好地被命名,这样的话在debug的时候会更方便。
将一个由本地(native)代码创建的线程添加到Java虚拟机中时,一个相应的java.lang.Thread对象将会被创建并且被添加大"main"线程组中(ThreadGroup)。对一个已经被添加到Java虚拟机中的线程调用AttachCurrentThread()方法的话并不会起什么作用。
通过JNI添加到虚拟机中的线程在它们退出之前必须调用DetachCurrentThread()。
翻译结束,其中最重要的就是在JNI中创建新的线程的话必须将这个线程添加(attach)到虚拟机中,然后获得一个专属于这个线程的JNIEnv变量,才能进行后续的调用,如果不进行线程的添加而且直接让多个线程共享一个JNIEnv变量来进行操作的话就会出现
EXCEPTION_ACCESS_VIOLATION (0xc0000005)的错误