使用JNI创建JFrame的死锁 我有一个java库,我需要从C++调用。使用JNI,我成功地调用了所需的方法,但有一个方法遇到了奇怪的死锁 这种有问题的方法在工作线程上创建一个JFrror,当从C++调用时,它永远不会返回。在谷歌搜索之后,我发现了一篇帖子,指出在MacOS中,当使用JNI时,与swing/awt的任何交互都不能从主线程完成。在更改代码以从工作线程调用该方法之后,jvm仍然陷于死锁,JNI调用永远不会返回
目前,我的代码如下所示(简化但基本相同): Java代码:使用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
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线程上完成?你可以尝试将你的代码与OpenJDKjava
可执行文件进行比较。我刚刚尝试使用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);
});
}