关于JNI的一些琐碎
首先在Java中调用C++实现的native方法,在该方法中,我又创建了一个线程,代码请见最下面。
1. 如何在这个新建的线程中调用Java代码?
JavaVM *g_jvm; DWORD __stdcall ThreadProc(void*) { MessageBoxA(NULL, "os thread", "demo", 0); JNIEnv *env = NULL; g_jvm->AttachCurrentThread((void**)&env, 0); jclass cls = env->FindClass("com/company/JNIDemo"); jmethodID mid = env->GetStaticMethodID(cls, "sayHello", "(Ljava/lang/String;)Ljava/lang/String;"); const char* name = "World"; jstring arg = env->NewStringUTF(name); jstring result = (jstring)env->CallStaticObjectMethod(cls, mid, arg); const char* str = env->GetStringUTFChars(result, 0); MessageBoxA(NULL, str, str, 0); env->ReleaseStringUTFChars(result, 0); return 0; }
g_jvm这个变量我会在Java调用的那个由C实现的native方法中初始化。在Java代码中我分别在main()和sayHello()两个函数中输出currentThread().getId(),它们的值是不同的。
值得注意的是,如果直接在C native中保存JNIEnv,在新建的线程中是无法使用它的。这里我仅实验了调用静态方法。
2. 如何在新建的操作系统线程中调用一个已有的Java对象非静态成员方法?
JavaVM *g_jvm; jobject g_obj; DWORD __stdcall ThreadProc(void*) { MessageBoxA(NULL, "os thread", "demo", 0); JNIEnv *env = NULL; g_jvm->AttachCurrentThread((void**)&env, 0); jclass cls = env->FindClass("com/company/JNIDemo"); jmethodID mid = env->GetMethodID(cls, "sayHello", "()Ljava/lang/String;"); jstring result = (jstring)env->CallObjectMethod(g_obj, mid); const char* str = env->GetStringUTFChars(result, 0); MessageBoxA(NULL, str, str, 0); env->ReleaseStringUTFChars(result, 0); env->DeleteLocalRef(cls); g_jvm->DetachCurrentThread(); return 0; }
JNIEXPORT jint JNICALL Java_com_company_JNIDemo_intMethod (JNIEnv *env, jobject obj, jint num) { g_obj = env->NewGlobalRef(obj); env->GetJavaVM(&g_jvm); CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); return num * num; }
此时,有必要确保Java那边的代码是多线程安全的!