简体   繁体   English

Maven 中 System.out.println 时重置线程中断标志

[英]Thread interrupted flag is reset when System.out.println in maven

Consider this program考虑这个程序

class Interrupted {
public static void main(String[] args) {
    assertFalse(Thread.currentThread().isInterrupted());
    assertFalse(Thread.currentThread().isInterrupted());
    Thread.currentThread().interrupt();
    System.out.println("hello world");
    assertTrue(Thread.currentThread().isInterrupted(), "first");
    assertTrue(Thread.currentThread().isInterrupted(), "second");
}

private static void assertFalse(boolean value) {
    if (value) {
        throw new RuntimeException("should be false");
    }
}

private static void assertTrue(boolean value, String text) {
    if (!value) {
        throw new RuntimeException("should be true " + text);
    }
}

} }

This program runs fine when you run it from the command line (java -cp target/classes example.sometest.Interrupted ), or from IntelliJ, or Eclipse.当您从命令行(java -cp target/classes example.sometest.Interrupted)、IntelliJ 或 Eclipse 运行该程序时,它运行良好。 But when you run it from "mvn test" then it fails.但是当你从“mvn test”运行它时,它就会失败。 The call to System.out.println resets the interrupted flag.对 System.out.println 的调用会重置中断标志。 What is going on?到底是怎么回事? My unit tests in one of my projects do System.out.println and expect the flag to not be reset.我的一个项目中的单元测试执行 System.out.println 并期望该标志不会被重置。

public class InterruptedTest {
@Test
void test() {
    Interrupted.main(null);
}

Output of "mvn test" “mvn 测试”的输出

[ERROR] example.sometest.InterruptedTest.test  Time elapsed: 0.019 s  <<< ERROR!
java.lang.RuntimeException: should be true first
at example.sometest.InterruptedTest.test(InterruptedTest.java:8)

You don't 'own' that flag - any method is more or less free to lower that and deal with the problem.你不“拥有”那个标志——任何方法或多或少都可以自由地降低它并处理问题。 It's a bit bizarre that the mvn test handler has some I/O op that will trigger on this flag (thus lowering it), but not show any error. mvn 测试处理程序有一些 I/O 操作会在这个标志上触发(从而降低它),但不显示任何错误,这有点奇怪。

Here's the central problem you're facing:这是您面临的核心问题:

All methods can be sorted into three categories:所有方法可以分为三类:

  • Completely ignore the interrupted flag;完全忽略中断标志; they don't abort when it is raised, and they do not lower it.它们在升高时不会中止,也不会降低。
  • Are specified to deal with it.被指定处理它。 For core libraries, these are easy: They always are declared to throws InterruptedException and they always deal with it by aborting immediately, lowering the flag , and throwing it.对于核心库,这些很简单:它们总是被声明为throws InterruptedException并且它们总是通过立即中止、降低 flag并抛出它来处理它。 This goes far: If the flag is on and you call Thread.sleep , for example, that call will immediately lower that flag and throw InterruptedException.这走得很远:例如,如果标志打开并且您调用Thread.sleep ,则该调用将立即降低该标志并抛出 InterruptedException。
  • The ¯\\ (ツ) /¯ methods: Think blocking file IO and such. ¯\\ (ツ) /¯ 方法:想想阻塞文件IO等。 Because of differences of underlying OS implementations, if you raise the interrupt flag on a thread whilst it is in the middle of a blocking operation (or start a blocking call when it is already up), then that blocking call may completely ignore it, or it may deal with it.由于底层操作系统实现的差异,如果您在线程处于阻塞操作中间时在线程上引发中断标志(或在它已经启动时启动阻塞调用),那么该阻塞调用可能会完全忽略它,或者它可能会处理它。 If it does, it will almost invariably lower the flag and throw IOException with a message indicating that it got interrupted.如果是这样,它几乎总是会降低标志并抛出IOException并带有一条消息,表明它被中断了。

And that's just the methods in core java.这只是核心java中的方法。 Because it is a global public state variable, it's pretty much impossible to try to write code to deal with this properly.因为它是一个全局公共状态变量,所以尝试编写代码来正确处理它几乎是不可能的。 What should occur on an interrupt is intentionally not clearly specified.没有明确规定在中断上应该发生什么。

Apparently something in maven is calling blocking output (that's logical: Every System.out call blocks in theory, and that's enough - if the OS supports it, something as trivial as System.out.println() will lower that flag and throw something), but is then ignoring the exception that falls out which is odd, but, I guess that's happening.显然,maven 中的某些东西正在调用阻塞输出(这是合乎逻辑的:理论上每个System.out调用都会阻塞,这就足够了 - 如果操作系统支持它,那么像System.out.println()这样微不足道的东西会降低该标志并抛出一些东西) ,但是然后忽略掉出来的异常,这很奇怪,但是,我想这正在发生。

Here's the key point though: That flag is extremely fragile - a ton of core methods, if called, will lower it, and it's not possible to know which ones (at the very least all methods declared to throw InterruptedException , but many more, and it's OS dependent which ones), so whatever code you wrote that is somehow dependent on this may need to be revisited.不过,关键点是:该标志非常脆弱-大量核心方法,如果调用,将降低它,并且不可能知道哪些(至少所有声明抛出InterruptedException方法,但更多,并且它依赖于操作系统),所以你编写的任何代码都可能需要重新访问。 There certainly is no --stop-messing-with-my-interrupt-flag maven option, I'm afraid :(当然没有--stop-messing-with-my-interrupt-flag Maven 选项,恐怕:(

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM