java - JNI 为同一个逻辑 Java 对象返回不同的作业
问题描述
我需要获取当前线程,但是java对象Thread,而不是windows内核GetCurrentThread()。但我有这个问题:代码:
void MyTest(JNIEnv* env) {
jobject t1 = GetJavaCurrentThread(env);
jobject t2 = GetJavaCurrentThread(env);
if (t1 != t2) {
std::cout << "this shouldn't happen. some informations:" << endl;
std::cout << t1 << " " << t2 << endl;
std::cout << GetJavaThreadName(env, t1) << " " << GetJavaThreadName(env, t2) << endl;
}
}
jobject GetJavaCurrentThread(JNIEnv* env) {
jclass threadClass = env->FindClass("java/lang/Thread");
jmethodID currentThreadMtd = env->GetStaticMethodID(threadClass, "currentThread", "()Ljava/lang/Thread;");
return env->CallStaticObjectMethod(threadClass, currentThreadMtd);
}
const char* GetJavaThreadName(JNIEnv* env, jobject thread) {
jclass threadClass = env->FindClass("java/lang/Thread");
jmethodID getNameMtd = env->GetMethodID(threadClass, "getName", "()Ljava/lang/String;");
jstring name = (jstring) env->CallObjectMethod(thread, getNameMtd);
return env->GetStringUTFChars(name, NULL);
}
为什么我从 jni 调用 Thread.currentThread 会得到不同的对象?
也许这是获取java端线程的错误方式?
解决方案
JNI 规范对本地引用的主题有这样的说法,这是您从以下函数中得到的CallStaticObjectMethod
:
为了实现本地引用,Java VM 为从 Java 到本地方法的每次控制转换创建一个注册表。注册表将不可移动的本地引用映射到 Java 对象,并防止对象被垃圾收集。所有传递给本机方法的 Java 对象(包括作为 JNI 函数调用的结果返回的对象)都会自动添加到注册表中。在本机方法返回后删除注册表,允许对其所有条目进行垃圾收集。
实现注册表的方法有很多种,例如使用表、链表或哈希表。尽管可以使用引用计数来避免注册表中的重复条目,但 JNI 实现没有义务检测和折叠重复条目。
这意味着允许实现为您提供对同一 Thread 对象的两个单独的本地引用。如果要测试对象相等性,请使用JNI IsSameObject 方法:
jboolean areEqual = env->IsSameObject(t1, t2);