本文介绍了OSX:JavaVM的,AWT / Swing和可能死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我真的很新的Java编程,因此我提前道歉,如果这听起来像一个愚蠢的问题。

I'm really new to java programming therefore I apologise in advance if this sounds like a stupid question.

我试图建立写在纯C一个简单的应用程序,它必须创建一个的JavaVM ,然后创建基于装载Java code一个新窗口 AWT / Swing的

I'm trying to build a simple application written in plain C, which must create a JavaVM and then create a new window by loading java code based on AWT/Swing.

的技术说明我心中已经了解到,在Mac OSX上只,的JavaVM必须从主线程不同线程,以便能够根据AWT创建的GUI被调用。

Following this technical note I'v learned that in Mac OSX only, JavaVM must be invoked from a thread different from the main thread in order to be able to create a GUI based on AWT.

因此​​,在我的C应用程序的的功能,我创建了一个执行的一切,从创建JAVAVM来创建图形用户界面的一个新的线程。

Therefore, in the main function of my C application I created a new thread that performs everything, from the creation of the javaVM to the creation of the GUI.

由于应用程序是不是在现实中那么简单,我将发布一个简化版本。

Since the application isn't in reality so simple, I will post a simplified version.

主要功能:

int main(int argc, char** argv)
{

    // Run-time loading of JavaVM framework

    void *result;

    result = dlopen("/System/Library/Frameworks/JavaVM.framework/JavaVM", RTLD_LAZY);
    if (!result) {
        printf("can't open library JavaVM: %s\n", dlerror());
    }
    else {
        printf("library JavaVM loaded\n");
    }

    /* Start the thread that runs the VM. */
    pthread_t vmthread;

    // create a new pthread copying the stack size of the primordial pthread
    struct rlimit limit;
    size_t stack_size = 0;
    int rc = getrlimit(RLIMIT_STACK, &limit);
    if (rc == 0) {
        if (limit.rlim_cur != 0LL) {
            stack_size = (size_t)limit.rlim_cur;
        }
    }


    pthread_attr_t thread_attr;
    pthread_attr_init(&thread_attr);
    pthread_attr_setscope(&thread_attr, PTHREAD_SCOPE_SYSTEM);
    pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
    if (stack_size > 0) {
        pthread_attr_setstacksize(&thread_attr, stack_size);
    }


    /* Start the thread that we will start the JVM on. */
    pthread_create(&vmthread, &thread_attr, startJava, (void *)&thread_data_struct);
    pthread_attr_destroy(&thread_attr);

    pthread_exit(NULL);

    return 0;
}

线程函数:

void *startJava(void *jvm_lib)
{

    JavaVMInitArgs args;

    const char* classpath = getenv("CLASSPATH");

    // determine classpath
    char* classpath_opt = str_printf("-Djava.class.path=%s", classpath);

    JavaVMOption* option = malloc(sizeof(JavaVMOption) * 2);
    option[0].optionString = classpath_opt;
    option[1].optionString = str_printf("-verbose:jni");

    args.version = JNI_VERSION_1_6;
    args.nOptions = 2;
    args.options = option;
    args.ignoreUnrecognized = JNI_FALSE; // don't ignore unrecognized options

    fptr_JNI_CreateJavaVM JNI_CreateJavaVM_fp = (fptr_JNI_CreateJavaVM)dl_dlsym(jvm_lib,
            "JNI_CreateJavaVM");

    int result = JNI_CreateJavaVM_fp(&jvm, (void**) &env, &args);
    free(option);
    free(classpath_opt);

    // launch java code
    jclass init_class = (*env)->FindClass(env, "org/classes/Loader");

    jmethodID load_id = (*env)->GetStaticMethodID(env, init_class, "Load",
        "(Ljava/lang/String;Lorg/classes/stuff;J)V");

    (*env)->CallStaticVoidMethod(env, init_class, load_id);
}

的Java code:(修订版)

package org.classes;

import java.awt.AWTException;
import java.awt.Component;
import java.awt.Frame;
import java.awt.image.BufferedImage;
import java.awt.EventQueue;

public class Loader {
    public static void Load(String baseDir, Stuff stuff, long nativePointer)
    {
      EventQueue.invokeLater(new Runnable() {
      public void run() {
              System.loadLibrary("drawingHelperLibrary");

              ...
              ...
              ...

              // start test window
              Frame frame = new Frame();
              frame.setSize(640,480);
              frame.setLocation(50, 50);
              frame.setVisible(true);

              }
       });
     }
}

以上所有code的成功执行,除了创建导致死锁或由于终端类似的东西窗口依然繁忙,没有任何CPU使用率,以及这两个线程仍然活着。

All of the above code executes successfully except for the creation of the window which causes a deadlock or something similar since terminal remains busy without any CPU usage and both threads remain alive.

如果我注释掉有关窗口创建线,应用成功执行并退出。

If I comment out the lines concerning the creation of the window, the application execute successfully and quit.

这是从jstack输出:

This is the output from jstack:

Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.4-b02-402 mixed mode):

"Attach Listener" daemon prio=9 tid=1040b1800 nid=0x11b888000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"Low Memory Detector" daemon prio=5 tid=103806000 nid=0x10b137000 runnable [00000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" daemon prio=9 tid=103805800 nid=0x10b034000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" daemon prio=9 tid=103804800 nid=0x10af31000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=9 tid=103804000 nid=0x10ae2e000 runnable [00000000]
   java.lang.Thread.State: RUNNABLE

"Surrogate Locker Thread (Concurrent GC)" daemon prio=5 tid=103803000 nid=0x10ad2b000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=8 tid=10409b800 nid=0x10ac28000 in Object.wait() [10ac27000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <7f3001300> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
    - locked <7f3001300> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=10409b000 nid=0x10ab25000 in Object.wait() [10ab24000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <7f30011d8> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:485)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
    - locked <7f30011d8> (a java.lang.ref.Reference$Lock)

"main" prio=5 tid=104000800 nid=0x10048d000 runnable [10048a000]
   java.lang.Thread.State: RUNNABLE
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)
    at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1827)
    - locked <7f30010a8> (a java.util.Vector)
    - locked <7f3001100> (a java.util.Vector)
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1724)
    at java.lang.Runtime.loadLibrary0(Runtime.java:823)
    - locked <7f3004e90> (a java.lang.Runtime)
    at java.lang.System.loadLibrary(System.java:1045)
    at sun.security.action.LoadLibraryAction.run(LoadLibraryAction.java:50)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.awt.NativeLibLoader.loadLibraries(NativeLibLoader.java:38)
    at sun.awt.DebugHelper.<clinit>(DebugHelper.java:29)
    at java.awt.Component.<clinit>(Component.java:566)
    at org.classes.Loader.Load(Loader.java:69)

"VM Thread" prio=9 tid=104096000 nid=0x10aa22000 runnable

"Gang worker#0 (Parallel GC Threads)" prio=9 tid=104002000 nid=0x103504000 runnable

"Gang worker#1 (Parallel GC Threads)" prio=9 tid=104002800 nid=0x103607000 runnable

"Concurrent Mark-Sweep GC Thread" prio=9 tid=10404d000 nid=0x10a6f0000 runnable
"VM Periodic Task Thread" prio=10 tid=103817800 nid=0x10b23a000 waiting on condition

"Exception Catcher Thread" prio=10 tid=104001800 nid=0x103401000 runnable
JNI global references: 913

我真的不知道还有什么我可以做。也许这是一个愚蠢的错误,但我没有足够的熟练使用这个Java-C组合,因为它是我在寻找它的第一次。

I really don't know what more can I do. Maybe it's a stupid mistake but I'm not skilled enough with this Java-C mix since it's the first time that I'm looking at it.

更新:我已经更新了Java code(感谢trashgod),但它仍然无法正常工作。
我缺少的东西吗?

UPDATE: I have updated the java code (thanks to trashgod) but it still doesn't work.Am I missing something?

推荐答案

我可以通过查看Eclipse项目是如何创建它的发射器来解决这个问题。您需要产卵的JVM的一个单独的线程,你都做了,但最主要的方法需要启动CFRunLoop。

I was able to resolve this issue by looking at how the Eclipse project creates its launchers. You need to spawn a separate thread for the JVM as you have done, but the main method needs to start the CFRunLoop.

有可能是您的特定实现一些额外的细节,但与此类似,目前在我们的案子:

There might be some additional details for your particular implementation, but something similar to this is currently working in our case:

...
#include <CoreServices/CoreServices.h>

static void dummyCallback(void * info) {}
...

...
if (stack_size > 0) {
    pthread_attr_setstacksize(&thread_attr, stack_size);
}

CFRunLoopRef loopRef = CFRunLoopGetCurrent();

/* Start the thread that we will start the JVM on. */
pthread_create(&vmthread, &thread_attr, startJava, (void *)&thread_data_struct);
pthread_attr_destroy(&thread_attr);

CFRunLoopSourceContext sourceContext = {
   .version = 0, .info = NULL, .retain = NULL, .release = NULL,
   .copyDescription = NULL, .equal = NULL, .hash = NULL,
   .schedule = NULL, .cancel = NULL, .perform = &dummyCallback };

CFRunLoopSourceRef sourceRef = CFRunLoopSourceCreate(NULL, 0, &sourceContext);
CFRunLoopAddSource(loopRef, sourceRef,  kCFRunLoopCommonModes);
CFRunLoopRun();
CFRelease(sourceRef);
...

您可以查看通过Eclipse执行此:

You can look through the Eclipse implementation here:

http://git.eclipse.org/c/equinox/rt.equinox.framework.git

这篇关于OSX:JavaVM的,AWT / Swing和可能死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 11:41