使用JNI创建JFrame的死锁 我有一个java库,我需要从C++调用。使用JNI,我成功地调用了所需的方法,但有一个方法遇到了奇怪的死锁 这种有问题的方法在工作线程上创建一个JFrror,当从C++调用时,它永远不会返回。在谷歌搜索之后,我发现了一篇帖子,指出在MacOS中,当使用JNI时,与swing/awt的任何交互都不能从主线程完成。在更改代码以从工作线程调用该方法之后,jvm仍然陷于死锁,JNI调用永远不会返回

使用JNI创建JFrame的死锁 我有一个java库,我需要从C++调用。使用JNI,我成功地调用了所需的方法,但有一个方法遇到了奇怪的死锁 这种有问题的方法在工作线程上创建一个JFrror,当从C++调用时,它永远不会返回。在谷歌搜索之后,我发现了一篇帖子,指出在MacOS中,当使用JNI时,与swing/awt的任何交互都不能从主线程完成。在更改代码以从工作线程调用该方法之后,jvm仍然陷于死锁,JNI调用永远不会返回,java,c++,macos,swing,java-native-interface,Java,C++,Macos,Swing,Java Native Interface,目前,我的代码如下所示(简化但基本相同): Java代码: import javax.swing.*; import java.awt.*; public class MyClass { private JFrame frame; private Thread thread; public void createFrame() { thread = new Thread(() -> { frame = new JF

目前,我的代码如下所示(简化但基本相同):

Java代码:

import javax.swing.*;
import java.awt.*;

public class MyClass
{
    private JFrame frame;
    private Thread thread;
    public void createFrame()
    {
        thread = new Thread(() -> {
            frame = new  JFrame("My Frame");
            frame.setTitle("JFrameCenter Position");
            frame.add(new JLabel("JFrame set to center of the screen", SwingConstants.CENTER), BorderLayout.CENTER);
            frame.setSize(400, 300);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLocationRelativeTo(null); 
            frame.setVisible(true);
        });
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            System.out.println("Exception on join Thread");
            e.printStackTrace();
        }
    }
}
C++代码

#include <iostream>
#include <jni.h>
#include <dlfcn.h>

#define JLI_DYLIB "/lib/jli/libjli.dylib"
#define JNI_CREATEVM_FUNC "JNI_CreateJavaVM"
typedef jint (JNICALL CreateJavaVM_t)(JavaVM **pvm, void **env, void *args);

void* DyLibHandler;
JavaVM *jvm;



void *GetStartJvmFunc(std::string javaHome) {
    std::string jliPath = javaHome.append(JLI_DYLIB);
    DyLibHandler = dlopen(jliPath.c_str(), RTLD_LAZY);
    if(!DyLibHandler)
    {
        return NULL;
    }
    void * jvmFunc = dlsym(DyLibHandler, JNI_CREATEVM_FUNC);
    if  (!jvmFunc)
    {
        dlclose(DyLibHandler);
        return NULL;
    }
    
    return jvmFunc;
}

void StartJvm(const char * javaHome, const char * classPath) {
    std::string jarsPath = "-Djava.class.path=";
    std::string home = "-Djava.home=";
    JavaVMOption* options = new JavaVMOption[3];   // JVM invocation options
    options[0].optionString = (char*)jarsPath.append(classPath).c_str();
    options[0].extraInfo = NULL;
    options[1].optionString = (char*)home.append(javaHome).c_str();
    options[1].extraInfo = NULL;
    options[2].optionString = "-Dsun.net.inetaddr.ttl=10";
    options[2].extraInfo = NULL;

    JavaVMInitArgs vm_args;
    vm_args.options = options;
    vm_args.nOptions = 3;
    vm_args.version = JNI_VERSION_1_8;
    
    JNIEnv *jniEnvironment;
    CreateJavaVM_t* createVMFunc = (CreateJavaVM_t*)GetStartJvmFunc(std::string(javaHome));
    jint rc = createVMFunc(&jvm, (void**)&jniEnvironment, &vm_args);
    delete[] options;
    if (rc != JNI_OK) {
        createVMFunc = NULL;
        exit(EXIT_FAILURE);
    }
}

void CreateJFrame(JNIEnv *jniEnvironment)
{
    jclass localHandler = jniEnvironment->FindClass("MyClass");
    if (!localHandler)
    {
        std::cout << "Could not Find LocalClass" << std::endl;
        exit(EXIT_FAILURE);
    }
    
    jclass classHandle = (jclass) jniEnvironment->NewGlobalRef(localHandler);
    jniEnvironment->DeleteLocalRef(localHandler);
    
    jmethodID constructorHandler = jniEnvironment->GetMethodID(classHandle, "<init>", "()V");
    if (!constructorHandler)
    {
        std::cout << "Could not find Constructor" << std::endl;
        exit(EXIT_FAILURE);
    }

    jmethodID createMethodHandler = jniEnvironment->GetMethodID(classHandle, "createFrame", "()V");
    if (!createMethodHandler)
    {
        std::cout << "Could not Find CreateFrame Method" << std::endl;
        exit(EXIT_FAILURE);
    }
    
    jobject localRef = jniEnvironment->NewObject(classHandle, constructorHandler);
    if(!localRef)
    {
        std::cout << "Could not instantiate MyClass" << std::endl;
        exit(EXIT_FAILURE);
    }

    jobject classInstance = jniEnvironment->NewGlobalRef(localRef);
    jniEnvironment->DeleteLocalRef(localRef);
    if (classInstance == nullptr)
    {
        std::cout << "Could not create global ref to MyClass instance" << std::endl;
        exit(EXIT_FAILURE);
    }
    
    jniEnvironment->CallVoidMethod(classInstance, createMethodHandler);
}

void SourceCallback (  void *info  ) {
    
    std::cout << "From Source Callback! Got Event" << std::endl;
}

void * ThreadProc(void * arg)
{
    JNIEnv *env = NULL;
    jint result =jvm->AttachCurrentThread((void **)&env, NULL);
    if( result != JNI_OK)
    {
        std::cout << "Error! Could not attach JNIEnv to thread (" << result << ")"<< std::endl;
        goto clean;
    }
    
    CreateJFrame(env);
    
    std::cout << "Deataching Thread" << std::endl;
    result = jvm->DetachCurrentThread();
    if(result != JNI_OK)
    {
        std::cout << "Error! could not deatached current thread (" << result << ")" << std::endl;
    }
    else{
        std::cout << "Done Deataching Thread" << std::endl;
    }
    
clean:
    std::cout << "Done Creating Frame" << std::endl;
    return NULL;
}

int main(int argc, const char * argv[])
{
    StartJvm(/*Java_Home path*/, /*Path to MyClass.class*/);
    pthread_t vmThread;
    pthread_create(&vmThread, NULL, ThreadProc, NULL);
    pthread_join(vmThread, NULL);
    std::cout << "UIThread is done" << std::endl;
    std::cout << "Waiting to Terminate program" << std::endl;
    std::string str;
    std::getline(std::cin, str);
}
#包括
#包括
#包括
#定义JLI_DYLIB“/lib/JLI/libjli.DYLIB”
#定义JNI_CREATEVM_FUNC“JNI_CreateJavaVM”
typedef jint(JNICALL CreateJavaVM_t)(JavaVM**pvm,void**env,void*args);
void*DyLibHandler;
JavaVM*jvm;
void*GetStartJvmFunc(std::string javaHome){
std::string jliPath=javaHome.append(JLI_DYLIB);
DyLibHandler=dlopen(jliPath.c_str(),RTLD_LAZY);
if(!DyLibHandler)
{
返回NULL;
}
void*jvmFunc=dlsym(DyLibHandler,JNI_CREATEVM_FUNC);
if(!jvmFunc)
{
dlclose(DyLibHandler);
返回NULL;
}
返回jvmFunc;
}
void StartJvm(const char*javaHome,const char*classPath){
std::string jarsPath=“-Djava.class.path=”;
std::string home=“-Djava.home=”;
JavaVMOption*options=newjavavmoption[3];//JVM调用选项
选项[0]。选项字符串=(char*)jarsPath.append(classPath.c_str();
选项[0]。extraInfo=NULL;
选项[1]。选项字符串=(char*)home.append(javaHome.c_str();
选项[1]。extraInfo=NULL;
选项[2]。选项字符串=“-Dsun.net.inetaddr.ttl=10”;
选项[2]。extraInfo=NULL;
JavaVMInitArgs vm_args;
vm_args.options=选项;
vm_args.nOptions=3;
vm_args.version=JNI_version_1_8;
JNIEnv*jniEnvironment;
CreateJavaVM_t*createVMFunc=(CreateJavaVM_t*)GetStartJvmFunc(std::string(javaHome));
jint rc=createVMFunc(&jvm,(void**)&jniEnvironment,&vm_参数);
删除[]个选项;
如果(rc!=JNI_OK){
createVMFunc=NULL;
退出(退出失败);
}
}
void CreateJFrame(JNIEnv*jniEnvironment)
{
jclass localHandler=jniEnvironment->FindClass(“MyClass”);
if(!localHandler)
{
std::cout DeleteLocalRef(localHandler);
jmethodID constructorHandler=jniEnvironment->GetMethodID(classHandle,“,”()V”);
if(!constructorHandler)
{

std::你有没有试过用SwingUtilities做你的UI?如果有帮助的话,我想知道,但是可能

public void createFrame()
{
    SwingUtilities.invokeAndWait(new Runnable() {
        frame = new  JFrame("My Frame");
        frame.setTitle("JFrameCenter Position");
        frame.add(new JLabel("JFrame set to center of the screen", SwingConstants.CENTER), BorderLayout.CENTER);
        frame.setSize(400, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null); 
        frame.setVisible(true);
    });
}

当然,你真正读到的是,它必须在AWT线程上完成?你可以尝试将你的代码与OpenJDK
java
可执行文件进行比较。我刚刚尝试使用SwingUtilities,同样的情况也发生了。主线程卡在
invokeAndAwait
上,
invokeAndAwait
挂起加载本机库ppose您可以尝试invokeLater而不是InvokeAndWait,我也尝试了
invokeLater
,同样的情况也发生了
public void createFrame()
{
    SwingUtilities.invokeAndWait(new Runnable() {
        frame = new  JFrame("My Frame");
        frame.setTitle("JFrameCenter Position");
        frame.add(new JLabel("JFrame set to center of the screen", SwingConstants.CENTER), BorderLayout.CENTER);
        frame.setSize(400, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null); 
        frame.setVisible(true);
    });
}