【问题标题】:Executing Java line by line逐行执行Java
【发布时间】:2016-06-25 13:24:52
【问题描述】:

我正在尝试设置我的 java 代码,以便它可以在任何代码执行点后停止。

我正在考虑将我的所有代码放在一个线程中,并在我希望它停止时调用Thread.interrupt()。请注意,如果正在运行任何线程阻塞方法(如 sleepjoinwait 等),此方法只会导致代码抛出 InterruptedException。否则它只会设置中断标志,我们必须在每一行之后通过isInterrupted()检查它。

所以现在我需要做的就是插入以下代码...

if (myThread.isInterrupted()) {
    System.exit(0);
}

在每一行代码之后。如果我的 java 代码存储在 String 中,我如何在代码的每个执行点之后插入这行代码?

我正在考虑在分号上使用 split 方法并在结果数组中的每个元素之间插入线程代码,但它不起作用,因为例如 for 循环有分号不代表语句的结尾.我想我也必须在右花括号上分开,因为它也代表代码语句的结尾。

编辑:解决方案尝试:

final String javaCode = "if (myString.contains(\"foo\")) { return true; } int i = 0;";
final String threadDelimiter = "if (thisThread.isInterrupted()) { System.exit(0); }";
final StringBuffer sb = new StringBuffer();

for (int i = 0; i < javaCode.length(); i++) {
    final char currChar = javaCode.charAt(i);

    sb.append(currChar);
    if ("{};".contains(currChar + "")) {
        sb.append(threadDelimiter);
    }
}

System.out.println(sb);

这段代码几乎是正确的,但它不适用于任何使用分号的循环。它也不适用于没有大括号的 for 循环。

【问题讨论】:

  • "我正在尝试设置我的 java 代码,以便它可以在任何代码执行点后停止。" - 什么?为什么?您是否正在尝试调试某些东西?如果是这样,您可以使用调试器暂停并逐行执行您的程序。否则,你的目标是什么?只需发送 SIGINT 就足以让您的程序退出。
  • 你到底为什么要在每一行代码之后这样做。代码运行速度很快,所以只做一个关键点,例如在长时间运行的循环开始时,等等。是否需要再过 0.000001 秒才被中断,这没关系,不是吗? 仅供参考:我的机器可以在 0.000001 秒内运行 200 条简单语句。
  • 我想要可中断的 java 代码,以防我得到长时间运行的 java 代码,我希望能够在经过一定时间后立即停止。另外,我不是在尝试调试代码。我得到了要运行的代码,我需要能够随时中断它。
  • @Andreas 你不知道我将要运行什么语句。我可能会得到进行大量 api 调用、数据库查询等的代码。你的机器的速度是无关紧要的。
  • 向您的程序发送SIGINTSIGTERM,它会立即退出。

标签: java string


【解决方案1】:

首先,如果您的目标是触发System.exit(),则无需将此类调用注入另一个线程然后中断该线程;只需调用 System.exit() 即可调用 otherThread.interrupt();,该过程将很快退出。

其次,您的计划不会实现您的目标。假设您在此语句周围添加了中断然后退出代码:

new Scanner(System.in).next();

如果没有向程序的 stdin 写入任何内容,则此语句将无限期阻塞,并且不会考虑线程中断。还有无数其他类似的代码 sn-ps 示例会导致线程阻塞。无论您注入的粒度如何,都可能永远无法达到您中断的检查。

第三,将源代码作为字符串进行操作是一条疯狂的道路。有exist 标准工具可将Java 语法解析为您可以安全操作的结构化数据类型。如果您必须进行源代码操作,请使用正确的设备。

第四,没有特别的理由需要与源代码交互来简单地注入额外的命令;编译源代码并使用bytecode injection 直接注入您的命令。字节码的语法比 Java 源代码更受限制,因此更容易安全地推理和变异。

除此之外,您根本不需要做任何这些

听起来您的目标是执行一些未知的 Java 代码 sn-p 但能够随时导致进程停止。这正是您的操作系统的设计目的 - 管理流程执行。为此,POSIX 提供了几个标准signals,您可以将其发送到进程以优雅地(或不太优雅地)导致该进程终止。向 Java 进程发送 SIGINT (Ctrl-C)、SIGTERMSIGHUP 将导致 JVM 启动其关闭序列,从而有效地触发 @ 987654340@.

JVM shuts down:

在第一阶段,所有注册的关闭挂钩(如果有)都以某种未指定的顺序启动,并允许同时运行直到它们完成。在第二阶段,如果 finalization-on-exit 已启用,则所有未调用的终结器都会运行。完成此操作后,虚拟机将停止。

换句话说,只要你prevent你从registering malicious shutdown hooks运行的代码或调用runFinalizersOnExit()发送这些信号都会导致JVM立即终止。

如果您的用例无法接受,请改为发送SIGKILL;操作系统将立即导致进程终止,而不给它运行关闭挂钩或终结器的机会。您也可以在 JVM 中调用 Runtime.halt() 来完成大致相同的事情。

【讨论】:

  • 所以这不会停止主线程吧?因为我不希望我的整个应用程序停止运行——我只想继续并执行给定的下一个 java 代码 sn-p。这是否意味着我需要在它们自己的进程中运行这些 sn-ps?
  • @Ogen 除了答案我认为你应该检查How do you dynamically compile and load external java classes?Sandbox against malicious code in a Java application 还有一个java sandbox library 具有可配置的最大运行时间。
  • @Ogen 是的,您应该在隔离的 JVM 中运行每个 sn-p(请注意您的原始示例称为 System.exit(),这同样会杀死您的主线程)。这是一种称为sandboxing 的标准做法。对于真正不受信任的代码,您最好在隔离的虚拟机中运行每个 sn-p,而不仅仅是一个进程。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-25
  • 2015-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-23
相关资源
最近更新 更多