为什么它保持 lib/modules 锁定?
Why does it keep lib/modules locked?
当我启动任何第三方应用程序时,例如从 Java 9 应用程序中记事本(但您可以使用其他任何东西),然后退出 Java 应用程序:
import java.io.*;
public class LaunchNotepad {
public static void main(String[] args) throws IOException {
Runtime.getRuntime().exec(new String[] {"C:\Windows\notepad.exe"});
}
}
启动的第三方应用程序一直锁定 Java 9 的 lib\modules
文件。这使得带有私有 JRE 的 Java 应用程序很难自行更新,因为无法重命名原始目录(包含 JRE)。这是 ProcessExplorer (Sysinternals) 的屏幕截图:
这闻起来像 Java 9 错误(报告为 JDK-8194734),但是 是否有在 Windows 上启动应用程序而不锁定的解决方法lib\modules
文件,例如通过使用外部(代理)应用程序将传递的参数简单地作为应用程序启动?
如果您有 Oracle Java 支持合同,您应该通过支持渠道询问何时会提供修复。
更新 - 基于https://bugs.openjdk.java.net/browse/JDK-8194734,当前答案可能是"when Java 11 is released"。但是 Oracle 可能会决定将修复程序反向移植到 Java 9 和 10。
如果您真的急需修复,请考虑执行以下操作:
下载 OpenJDK 源代码并构建您自己的 JVM。
找出错误所在。你似乎知道它是什么,所以应该不难找出在哪里看。
修复该错误。
将修复作为补丁贡献给 OpenJDK 项目。
这将增加问题在标准代码库和由此产生的发行版中更快得到修复的可能性。它还将为您提供 in-house 测试和愿意使用您的 "fixed" JVM 的客户的解决方法。
我提到了一种可能的解决方法,涉及重新编写您拒绝的代码。还有其他人。据我所知,没有任何解决方法不涉及您的工作,无论是哪种方式。
我fixed this bug。这算作解决方法吗? :)
否则,一些解决方法确实是可行的。
解决方法 1:使用 awt.Desktop
扫描了Java个资源,发现awt.Desktop
可以为我们调用ShellExecute
不幸的是,此方法不允许传递命令行参数。您可以将临时批处理文件写入磁盘并启动它作为解决方法。
import java.io.*;
import java.awt.Desktop;
public class LaunchNotepad {
public static void main(String[] args) throws IOException {
File program = new File("C:\Windows\notepad.exe");
Desktop.getDesktop().open(program);
}
}
解决方法 2:使用 PsExec 作为代理
SysInternals PsExec 不会将文件继承到以它启动的进程中。请记住使用 -d
参数,否则 PsExec 本身将保存该文件。
无法使用 cmd.exe
作为代理,因为它总是继承句柄。
解决方法 3:制作您自己的代理
您将需要使用两个 WINAPI 之一:CreateProcess (specifying bInheritHandles=FALSE
) or ShellExecute。
当我启动任何第三方应用程序时,例如从 Java 9 应用程序中记事本(但您可以使用其他任何东西),然后退出 Java 应用程序:
import java.io.*;
public class LaunchNotepad {
public static void main(String[] args) throws IOException {
Runtime.getRuntime().exec(new String[] {"C:\Windows\notepad.exe"});
}
}
启动的第三方应用程序一直锁定 Java 9 的 lib\modules
文件。这使得带有私有 JRE 的 Java 应用程序很难自行更新,因为无法重命名原始目录(包含 JRE)。这是 ProcessExplorer (Sysinternals) 的屏幕截图:
这闻起来像 Java 9 错误(报告为 JDK-8194734),但是 是否有在 Windows 上启动应用程序而不锁定的解决方法lib\modules
文件,例如通过使用外部(代理)应用程序将传递的参数简单地作为应用程序启动?
如果您有 Oracle Java 支持合同,您应该通过支持渠道询问何时会提供修复。
更新 - 基于https://bugs.openjdk.java.net/browse/JDK-8194734,当前答案可能是"when Java 11 is released"。但是 Oracle 可能会决定将修复程序反向移植到 Java 9 和 10。
如果您真的急需修复,请考虑执行以下操作:
下载 OpenJDK 源代码并构建您自己的 JVM。
找出错误所在。你似乎知道它是什么,所以应该不难找出在哪里看。
修复该错误。
将修复作为补丁贡献给 OpenJDK 项目。
这将增加问题在标准代码库和由此产生的发行版中更快得到修复的可能性。它还将为您提供 in-house 测试和愿意使用您的 "fixed" JVM 的客户的解决方法。
我提到了一种可能的解决方法,涉及重新编写您拒绝的代码。还有其他人。据我所知,没有任何解决方法不涉及您的工作,无论是哪种方式。
我fixed this bug。这算作解决方法吗? :)
否则,一些解决方法确实是可行的。
解决方法 1:使用 awt.Desktop
扫描了Java个资源,发现awt.Desktop
可以为我们调用ShellExecute
不幸的是,此方法不允许传递命令行参数。您可以将临时批处理文件写入磁盘并启动它作为解决方法。
import java.io.*;
import java.awt.Desktop;
public class LaunchNotepad {
public static void main(String[] args) throws IOException {
File program = new File("C:\Windows\notepad.exe");
Desktop.getDesktop().open(program);
}
}
解决方法 2:使用 PsExec 作为代理
SysInternals PsExec 不会将文件继承到以它启动的进程中。请记住使用 -d
参数,否则 PsExec 本身将保存该文件。
无法使用 cmd.exe
作为代理,因为它总是继承句柄。
解决方法 3:制作您自己的代理
您将需要使用两个 WINAPI 之一:CreateProcess (specifying bInheritHandles=FALSE
) or ShellExecute。