timob / jnigi

Golang Java JNI library
BSD 2-Clause "Simplified" License
163 stars 44 forks source link

go won't wait the java thread finish #22

Closed LeungJacky closed 3 years ago

LeungJacky commented 4 years ago

i try to use JNIGI to call a .jar main method(using thread inside the jar program, should took 5x sec to run) but the go program ended so fast()

package threading;
public class TestThread implements Runnable{
    @Override
    public void run()  {
        System.out.println("here is TestThread");
        try{
            System.out.println("try");
            int i=0;
            while(i< 10){
                System.out.println("here is looping: "+i);
                Thread.sleep(5000);
                i++;
            }
        }catch(Exception e){
            System.out.println("exception on sleep");
        }
        System.out.println("here is TestThread after sleep");
    }
}
import threading.TestThread;
public class Main{
    public static void main(String [] args){
        System.out.println("here is Main");

        Thread tt = new Thread(new TestThread());
        tt.start();
        System.out.println("here is Main 8");

    }
}
timob commented 4 years ago

Can you post the go program you are using to call the main?

LeungJacky commented 4 years ago

oh, sorry for missing the go program

package main

// #cgo CFLAGS: -I/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/include
// #cgo CFLAGS: -I/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/include/darwin
// #include <jni.h>
import "C"
import (
    "fmt"
    "github.com/timob/jnigi/"
    "log"
)

func main() {

    _, env, err := jnigi.CreateJVM(jnigi.NewJVMInitArgs(false, true, jnigi.DEFAULT_VERSION, []string{"-Xcheck:jni","-Djava.class.path=./thread.jar"}))

    if err != nil {
        log.Fatal(err)
    }
    strArr := jnigi.WrapJObject(0, "java/lang/String", true)
    test, err := env.CallStaticMethod("Main", "main", jnigi.Void,strArr)
    if err != nil {
        log.Fatal(err)
        fmt.Printf("have error: %d\n", test)
    } else {
        fmt.Printf("no error: ")
    }

    //time.Sleep(60 * time.Second)
    println("go program ended")
}
LeungJacky commented 4 years ago

https://drive.google.com/file/d/1yKfzXsqOp7BABPSihf8sf2EZfyKmVInn/view?usp=sharing thread.jar here is the jar file for testing java -jar thread.jar

timob commented 4 years ago

Please see https://golang.org/ref/spec#Program_execution:

Program execution begins by initializing the main package 
and then invoking the function main.When that function 
invocation returns, the program exits. It does not wait for other (non-main) 
goroutines to complete.

This also applies to threads created by the JVM, when program exits it doesn't wait for them to complete.

timob commented 4 years ago

If you've got an email maybe i can help with what you are trying to do? otherwise i dont see the issue here.

LeungJacky commented 4 years ago

I am trying to start jvm and launch a custom java program with class encryption for my fyp. I hope to start the jvm to run the main method, and it can wait untill the jvm done all the job, I tried start jvm with c++ jni call, node js jni call, and also go jni call, but only c++ jni call can wait untill the thread run, It seems the mechanism is difference that lang go (and cgo) is a good option to create both Mac, Linux and Windows version application , but It seems hard to know that what is the end time of the jvm from go.🤔

dbarganski commented 4 years ago

You need to call DestroyJavaVM() from main GO thread. Otherwise program will exit without waiting for JVM running thread completion.

Submitted a PR adding the call.

timob commented 4 years ago

@dbarganski 👌 Cool, sounds exactly what @LeungJacky was looking for. Will look at PR.

timob commented 4 years ago

PR here: https://github.com/timob/jnigi/pull/34

timob commented 4 years ago

Probably should mention this the docs somewhere.

timob commented 3 years ago

I've added DestroyJavaVM to example. So hope this will be some kind of documentation.