java - 如何从 Java 代理停止/暂停主程序/线程

标签 java multithreading exit byte-buddy javaagents

我有一个 gradle 测试任务,它运行来自给定文件的测试列表。 有时,任何特定的测试执行都会卡住,不会继续执行列表中的下一个测试。

为此,我试图添加一个 java 代理,它将检测每次测试执行中的超时并在这种情况下调用 System.exit()。 (我知道调用 System.exit() 似乎是一个轻率的决定,但抛出异常似乎并没有停止测试执行) Java 代理使用字节伙伴建议来执行此操作。

public class TimerAdvice {
    public static CountDownLatch latch;

    @Advice.OnMethodEnter
    static long enter(@Advice.This Object thisObject,
                      @Advice.Origin String origin,
                      @Advice.Origin("#t #m") String detaildOrigin) throws InterruptedException {
        System.out.println("Timer Advice Enter thread: " + Thread.currentThread().getName() + " time: " + Instant.now().toString());

        latch = new CountDownLatch(1);

        ThreadFactory factory = new MyThreadFactory(new MyExceptionHandler());
        ExecutorService threadPool = Executors.newFixedThreadPool(1, factory);
        threadPool.execute(new TestCallable());

        return System.nanoTime();
    }

    @Advice.OnMethodExit (onThrowable = Throwable.class)
    static void onExit(@Advice.Origin Method method) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        System.out.println("Timer Advice Exit thread: " + Thread.currentThread().getName() + " time: " + Instant.now().toString());
        System.out.println("Counting down");
        latch.countDown();
    }
}

基本上,这将产生一个后台线程,该线程将等待直到锁存器倒计时。

public class TestCallable implements Runnable {
    @Override
    public void run()  {
        try {
            latch.await(10, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new IllegalStateException(e.getMessage());
        }
        if(latch.getCount() > 0) {
            System.err.println("Callable thread"
                    + Thread.currentThread().getName() +
                    "TIMEOUT OCCURED!!!!");
            System.exit(1);
        }
    }
}

闩锁 countDown() 方法将由处理 OnExit 通知的方法调用。 在此之前,线程将等待指定的超时时间。

我的问题是,为什么 System.exit() 调用不影响测试执行/jvm 当该线程调用System.exit()时,测试线程仍然继续执行,就好像什么事都没发生过一样。我想在此时停止执行测试。

关于在检测到超时时我应该如何停止整个测试执行过程有什么建议吗?

最佳答案

OP 说我关于安全经理的评论帮助他找到了根本原因,所以我将其转换为答案:

如文件所示,System.exit()如果有安全管理器阻止它这样做,则不会关闭 JVM。不过,在这种情况下,您应该会看到一个 SecurityException

Gradle issue #11195 中的讨论提到了 Kafka 偶尔意外退出的问题,并建议 Spring-Kafka 的安全管理器策略阻止它这样做。这是针对 Spring-Kafka 的,但是 - 如果我理解正确的话 - 不是针对 Gradle。


另一个极端情况是关闭 Hook :调用 System.exit() 的线程会阻塞,直到 JVM 终止。如果关闭 Hook 向该线程提交任务,则会导致死锁。

关于java - 如何从 Java 代理停止/暂停主程序/线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67503280/

相关文章:

java - 扩展接口(interface)与通过匿名类实例化

c# - 高优先级的自定义命令Windows服务

c++ - 在一个线程中等待 2 个不同的事件

python - 如何在 Pygame 中退出全屏模式?

c# 控制台应用程序保持在任务计划程序 Windows 2016 中运行的状态

java - 在 Android ICS 操作栏中显示菜单项

java - Spring websockets : sending a message to an offline user - messages not enqueued in message broker

java - 从给定的 1 和 0 字符串中获取一个字节

c - Freertos + STM32 - malloc 线程内存溢出

android - 是否有可能以某种方式处理 Android 应用程序的滑动退出?