带有 RMI 的 Maven exec 插件 java 目标提前退出

问题描述 投票:0回答:1

org.codehaus.mojo:exec-maven-plugin:3.3.0
插件“java”目标文档指出“一旦所有已知的非守护线程退出,守护线程就会加入并中断”。这不是我在涉及 RMI 线程的一些代码中观察到的情况(除了我不知道什么是“未知”线程),我想知道为什么。这是一个错误,还是我错过了什么?

更多详情

我的“服务器”程序启动一个非守护线程(通过 RMI),当我使用“java”目标运行它时,JVM 在到达

main
方法末尾时退出。由于非守护线程仍在运行,我预计它会继续运行。当我使用直接调用
java
运行它时,正如预期的那样,即使在
main
完成后,程序也会继续运行。

代码

这是服务器。

public class Server {
  public static void main(String[] args) throws Exception {
    Registry registry = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
    RemoteTest engine = new RemoteTestImpl();
    RemoteTest stub = (RemoteTest) UnicastRemoteObject.exportObject(engine, 0);
    registry.rebind("RemoteTestJ2", stub);
    Thread.sleep(3000);
    Thread.getAllStackTraces().keySet().forEach(thread -> {
      System.out.println("Thread: " + thread.getName() + " is daemon: " + thread.isDaemon());
    });
  }
}

这是客户。

public class User {
  public static void main(String[] args) throws Exception {
    Registry registry = LocateRegistry.getRegistry(Registry.REGISTRY_PORT);
    RemoteTest rem = (RemoteTest) registry.lookup("RemoteTestJ2");
    while(true) {
      System.out.println("Tested: " + rem.test(0, 1));
    }
  }
}

完整代码在这里

重现问题

  • git clone https://github.com/oliviercailloux/JGradLib-Additioner.git ; cd JGradLib-Additioner ; git checkout rmistop
  • 启动服务器:
    mvn -Dexec.mainClass=io.github.oliviercailloux.javagrade.graders.Server compile org.codehaus.mojo:exec-maven-plugin:3.3.0:java
  • 启动客户端(并行,在启动服务器之后):
    java -cp "target/classes/" io.github.oliviercailloux.javagrade.graders.User

预期:RMI 机制在后台启动非守护线程并阻止 JVM 退出,以便服务器无限期地保持活动状态,并且客户端永远打印

test
调用的结果。

实际:服务器启动,RMI 按预期启动非守护线程(以及守护线程),服务器休眠三秒,打印其线程,然后退出。与此同时,客户端开始向终端发送

test
调用的结果,但三秒后,崩溃并显示堆栈跟踪,抱怨它无法再到达远程端。

没有问题的变体

exec
插件和RMI方面似乎都需要触发这种奇怪的行为。

如果使用

java -cp "target/classes/" io.github.oliviercailloux.javagrade.graders.Server
而不是
exec
插件运行服务器,服务器将按预期运行。

或者,如果我更改服务器代码以简单地启动一个保持忙碌的新线程(在 while 循环中休眠),服务器将继续按预期运行。

multithreading rmi maven-exec-plugin
1个回答
0
投票

pom.xml

不要使用

exec:java
,使用
exec:exec

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>io.github.oliviercailloux.grading</groupId>
    <artifactId>additioner</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <!--
        <maven.compiler.release>17</maven.compiler.release>
        -->
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>3.0.0</version>
                <executions>
                    <execution>
                        <id>run-java-program</id> <!-- Unique identifier for this execution -->
                        <phase>custom-phase</phase>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <executable>java</executable>
                    <workingDirectory>${project.directory}</workingDirectory>
                    <arguments>
                        <argument>-Dsun.rmi.transport.tcp.logLevel=VERBOSE</argument>
                        <argument>-Dsun.rmi.transport.logLevel=VERBOSE</argument>
                        <argument>-classpath</argument>
                        <classpath/>
                        <!-- Replace with your main class -->
                        <argument>io.github.oliviercailloux.javagrade.graders.Server</argument>
                        <!-- Replace with your program arguments -->
                        <!--
                       <argument>arg1</argument>
                       <argument>arg2</argument>
                       -->
                        <!-- Add more arguments as needed -->
                    </arguments>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

运行命令

mvn clean package exec:exec

您的服务器可以删除

Thread.sleep(3000);
    Thread.getAllStackTraces().keySet().forEach(thread -> {
      System.out.println("Thread: " + thread.getName() + " is daemon: " + thread.isDaemon());
    });
© www.soinside.com 2019 - 2024. All rights reserved.