首页 > 解决方案 > 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端线程的错误方式?

标签: javajava-native-interface

解决方案


JNI 规范对本地引用的主题有这样的说法,这是您从以下函数中得到的CallStaticObjectMethod

为了实现本地引用,Java VM 为从 Java 到本地方法的每次控制转换创建一个注册表。注册表将不可移动的本地引用映射到 Java 对象,并防止对象被垃圾收集。所有传递给本机方法的 Java 对象(包括作为 JNI 函数调用的结果返回的对象)都会自动添加到注册表中。在本机方法返回后删除注册表,允许对其所有条目进行垃圾收集。

实现注册表的方法有很多种,例如使用表、链表或哈希表。尽管可以使用引用计数来避免注册表中的重复条目,但 JNI 实现没有义务检测和折叠重复条目。

这意味着允许实现为您提供对同一 Thread 对象的两个单独的本地引用。如果要测试对象相等性,请使用JNI IsSameObject 方法

jboolean areEqual = env->IsSameObject(t1, t2);

推荐阅读