代码之家  ›  专栏  ›  技术社区  ›  Павел

从新的JNI线程通知Java

  •  0
  • Павел  · 技术社区  · 4 年前

    我制作了一个调用JNI的Java程序,它在JNI中创建了一个“JNICallback”线程,并在其中执行env-attachCurrentThreadAsDaemon()

    我做标准的事情,比如 synchronized -> wait, synchronized -> notifyAll ,使用 static final Object 如果我在Eclipse下运行它,一切正常。

    但如果我将其导出为“可运行jar文件”并在同一JVM下运行,我会看到我的JNI程序调用 monitorEnter, notifyAll, monitorExit 没有错误,但是Java没有被通知。 在调试器中,我看到JNI和Java中使用的同一对象的ObjectId不同,这对我来说是可疑的(下面的代码中是names OnConnectionEvent) 我甚至将通知代码从JNI移动到Java,并使用来自JNI的静态void方法调用,执行同步->notifyAll在Java中,但这只显示等待线程在不同的ObjectId上等待,所以我猜这就是原因。

    ...
        static final Object onConnectEvent = new Object();
    ...
        Thread dogServerConnect,...;
    ...
        public MainClass(){
            dogServerConnect = runDog(new ServerConnectionWatchDog(), "onServerConnect");
            someJNIstuffPlusNewThreadsCreation();
    ...
        
        static void onJNICallbackEvent(int type) {
            switch (type) {
            case 1 -> {
                synchronized(onConnectEvent) {
                    onConnectEvent.notifyAll();
                     ^^^^^ got to this line from JNI, just fine
                }
    ...
        class ServerConnectionWatchDog implements Runnable {
            @Override
            public void run() {
                while(true)
                    synchronized(onConnectEvent) {
                        try {
                            onConnectEvent.wait();
                            for (var l : listeners) {
    ^^^^^^^^^^^^^^^^^^^^^^^^^ never come to this line
    ...
    

    同样,这在Eclipse下确实工作得很好,但由于某些原因,作为单独的jar文件失败。

    我的意思是,对于正在等待的线程,Eclipse向我显示“正在等待:对象(id=48)”,对于“notifyAll”执行之前的本机线程,Eclipse向我显示“拥有:对象(id=50)”。可能这是因为我手动暂停等待的线程,以查看对象id(然后再次运行它,这不是原因) 我会错过什么?

    0 回复  |  直到 4 年前
        1
  •  0
  •   Павел    4 年前

    在Android常见问题解答中找到了答案: why didn't FindClass find my class . 虽然我的环境不是Android,但它仍然有意义。 问题是,环境->FindClass展开Java堆栈以查找调用方类并使用其类加载器。 此解决方案防止EclipseJarrLoader创建重复的静态对象。 也许有人会说,做环境->JNI中新创建的本机线程中的FindClass是一个糟糕的设计,至少要谨慎使用。