Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
这真的是从Java代码启动第二个JVM的最佳方式吗?_Java_Jvm_Multiprocessing - Fatal编程技术网

这真的是从Java代码启动第二个JVM的最佳方式吗?

这真的是从Java代码启动第二个JVM的最佳方式吗?,java,jvm,multiprocessing,Java,Jvm,Multiprocessing,这是我的后续行动,我有点不好意思问这个。。。但无论如何:您如何以独立于系统的方式从独立Java程序启动第二个JVM?并且不依赖例如JAVA_HOME之类的env变量,因为它可能指向与当前运行的JRE不同的JRE。我想出了下面的代码,它实际上可以工作,但感觉有点尴尬: public static void startSecondJVM() throws Exception { String separator = System.getProperty("file.separator");

这是我的后续行动,我有点不好意思问这个。。。但无论如何:您如何以独立于系统的方式从独立Java程序启动第二个JVM?并且不依赖例如JAVA_HOME之类的env变量,因为它可能指向与当前运行的JRE不同的JRE。我想出了下面的代码,它实际上可以工作,但感觉有点尴尬:

public static void startSecondJVM() throws Exception {
    String separator = System.getProperty("file.separator");
    String classpath = System.getProperty("java.class.path");
    String path = System.getProperty("java.home")
                + separator + "bin" + separator + "java";
    ProcessBuilder processBuilder = 
                new ProcessBuilder(path, "-cp", 
                classpath, 
                AnotherClassWithMainMethod.class.getName());
    Process process = processBuilder.start();
    process.waitFor();
}

另外,当前运行的JVM可能是用第二个JVM不知道的一些其他参数(-D,-X…,…)启动的。

我不清楚您是否总是希望使用完全相同的参数、类路径或其他任何参数(特别是-X类的东西——例如,为什么子进程需要与父进程相同的堆设置)启动辅助进程时

我更喜欢使用某种外部配置来为孩子们定义这些属性。这需要更多的工作,但我认为最终你需要灵活性


要查看可能的配置设置的范围,您可以查看Eclipse中的“运行配置”设置。其中有很多值得配置的选项卡。

我认为答案是“是”。这可能与使用系统独立代码在Java中所做的一样好。但请注意,即使这样,也只是相对独立于系统。例如,在某些系统中:

  • 可能未设置JAVA_HOME变量
  • 用于启动JVM的命令名可能不同(例如,如果它不是Sun JVM),或者
  • 命令行选项可能不同(例如,如果它不是Sun JVM)

  • 如果我的目标是在启动(第二个)JVM时实现最大的可移植性,我想我会使用包装器脚本来实现这一点。

    查找代码当前运行的java可执行文件(即问题示例代码中的“path”变量)ApacheAnt中有一个实用方法可以帮助您,您不必使用ant构建代码,只需将其用作库,就可以使用这个方法

    它是:

    org.apache.tools.ant.util.JavaEnvUtils.getJreExecutable(“java”)

    它负责处理其他人提到的不同JVM供应商的特殊情况(看看它的源代码,有比我想象的更多的特殊情况)


    它位于ant.jar中。ant是在Apache许可证下分发的,因此希望您可以随意使用它。

    以下是一种使用
    ProcessHandle.current().info().command()确定运行当前JVM的java可执行文件的方法。

    ProcessHandle
    API也应该允许获取参数。如果新JVM可用,此代码将使用它们,仅使用另一个示例类替换当前类名。(如果不知道当前主类的名称,则在参数中查找该主类会变得更困难,但在本演示中,它只是“This”您可能希望重用相同的JVM选项或其中的一些选项,但不要重用程序参数。)

    但是,对我来说(openjdk 11.0.2版,Windows 10),ProcessInfo.arguments()是空的,因此执行回退
    else
    路径

    package test;
    import java.lang.ProcessBuilder.Redirect;
    import java.lang.management.ManagementFactory;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Optional;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;
    
    public class TestStartJvm {
        public static void main(String[] args) throws Exception {
            ProcessHandle.Info currentProcessInfo = ProcessHandle.current().info();
            List<String> newProcessCommandLine = new LinkedList<>();
            newProcessCommandLine.add(currentProcessInfo.command().get());
    
            Optional<String[]> currentProcessArgs = currentProcessInfo.arguments();
            if (currentProcessArgs.isPresent()) { // I know about orElse, but sometimes isPresent + get is handy
                for (String arg: currentProcessArgs.get()) {
                    newProcessCommandLine.add(TestStartJvm.class.getName().equals(arg) ? TargetMain.class.getName() : arg);
                }
            } else {
                System.err.println("don't know all process arguments, falling back to passed args array");
                newProcessCommandLine.add("-classpath");
                newProcessCommandLine.add(ManagementFactory.getRuntimeMXBean().getClassPath());
                newProcessCommandLine.add(TargetMain.class.getName());
                newProcessCommandLine.addAll(List.of(args));
            }
    
            ProcessBuilder newProcessBuilder = new ProcessBuilder(newProcessCommandLine).redirectOutput(Redirect.INHERIT)
                    .redirectError(Redirect.INHERIT);
            Process newProcess = newProcessBuilder.start();
            System.out.format("%s: process %s started%n", TestStartJvm.class.getName(), newProcessBuilder.command());
            System.out.format("process exited with status %s%n", newProcess.waitFor());
        }
    
        static class TargetMain {
            public static void main(String[] args) {
                System.out.format("in %s: PID %s, args: %s%n", TargetMain.class.getName(), ProcessHandle.current().pid(),
                        Stream.of(args).collect(Collectors.joining(", ")));
            }
        }
    }
    
    封装测试;
    导入java.lang.ProcessBuilder.Redirect;
    导入java.lang.management.ManagementFactory;
    导入java.util.LinkedList;
    导入java.util.List;
    导入java.util.Optional;
    导入java.util.stream.collector;
    导入java.util.stream.stream;
    公共类TestStartJvm{
    公共静态void main(字符串[]args)引发异常{
    ProcessHandle.Info currentProcessInfo=ProcessHandle.current().Info();
    List newProcessCommandLine=newlinkedlist();
    newProcessCommandLine.add(currentProcessInfo.command().get());
    可选的currentProcessArgs=currentProcessInfo.arguments();
    if(currentProcessArgs.isPresent()){//我知道orElse,但有时isPresent+get很方便
    for(字符串arg:currentProcessArgs.get()){
    newProcessCommandLine.add(TestStartJvm.class.getName().equals(arg)?TargetMain.class.getName():arg);
    }
    }否则{
    System.err.println(“不知道所有进程参数,返回到传递的参数数组”);
    添加(“-classpath”);
    添加(ManagementFactory.getRuntimeMXBean().getClassPath());
    newProcessCommandLine.add(TargetMain.class.getName());
    newProcessCommandLine.addAll(参数列表);
    }
    ProcessBuilder newProcessBuilder=newProcessBuilder(newProcessCommandLine).redirectOutput(Redirect.INHERIT)
    .redirectError(Redirect.INHERIT);
    Process newProcess=newProcessBuilder.start();
    System.out.format(“%s:进程%s已启动%n”,TestStartJvm.class.getName(),newProcessBuilder.command());
    System.out.format(“进程退出,状态为%s%n”,newProcess.waitFor());
    }
    静态类TargetMain{
    公共静态void main(字符串[]args){
    System.out.format(“in%s:PID%s,args:%s%n”,TargetMain.class.getName(),ProcessHandle.current().PID(),
    Stream.of(args.collect(collector.joining(“,”));
    }
    }
    }
    
    在Java 9中添加
    ProcessHandle
    之前,我做了如下操作来查询当前JVM的命令行:

    • 让用户传递或配置“PID到命令行”命令模板;在Windows下,这可能是
      wmic进程,其中'processid=%s'获取命令行/格式:列表
    • 使用
      java.lang.management.ManagementFactory.getRuntimeMXBean().getPid()
      确定PID
    • 展开命令模板;执行;解析其输出

    JVM的配置文件是个好主意。我认为它应该可以在对话框中编辑,这样用户就可以但不必调整参数(很像Eclipse示例)。谢谢。Wha