在 try 块完成后延迟 Finally 块
Delay in the Finally block after try block completion
我正在尝试 运行 下面的并发代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws
InterruptedException {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
executor.submit(new Task());
System.out.println("Shutdown executor");
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
System.err.println("tasks interrupted");
} finally {
if (!executor.isTerminated()) {
System.err.println("cancel non-finished tasks");
}
executor.shutdownNow();
System.out.println("shutdown finished");
}
}
static class Task implements Runnable {
public void run() {
try {
int duration = 6;
System.out.println("Running Task!");
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出为:
Shutdown executor
Running Task!
shutdown finished
cancel non-finished tasks
java.lang.InterruptedException: sleep interrupted
根据输出,finally 块似乎被跳过,finally 块之后的代码先执行,然后再执行 finally 块。这是否与 try/catch 块完成后最终执行的代码的正常流程相矛盾?
编辑:已尝试
System.out.flush();
System.err.flush();
每次按照其中一项建议打印后,输出仍然相同。
编辑:
我正在使用在线编译器。
我想您希望这两个跟踪被颠倒,因为它们是以相反的顺序声明的:
shutdown finished
cancel non-finished tasks
我认为问题来自 System.err
和 System.out
的混合。
这些不是相同的流。所以它们的 flushing 和它们的 displaying 可能在不同的时间执行。
根据显示输出的 application/system(IDE、OS 命令行、在线 compiler/executor),至少有两件事可能会导致排序问题:
- 这些流的 autoflush 可能启用或未启用
- application/system 的 "output/console" 中这两个流之间的跟踪显示顺序可能不同步。
作为根据时间线显示输出的解决方法:
在每次 print()
调用后刷新流(System.out.flush()
和 System.err.flush()
)。
它可能有效,但不能保证 application/system 写入输出可能不会通过时间线同步这两个流的显示。
尽量仅使用 System.out
,仅在程序将退出的错误情况下使用 System.err
。
它将减少交错的可能性。
如果最后一个想法不合适,因为清楚地区分两种输出很重要,请使用允许精确跟踪信息的日志库(Logback 或 Log4j2,最好在 facade 中带有 SLF4J) (日期、时间、严重级别...)并按照程序流时间线的实际顺序阅读它们。
这是仅使用 System.out
的相同代码:
我为输出的预期顺序添加了 //1
、//2
、...注释。
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
executor.submit(new Task());
System.out.println("Shutdown executor"); // 1
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
System.out.println("tasks interrupted"); // not invoked because caught in Task.run()
} finally {
if (!executor.isTerminated()) {
System.out.println("cancel non-finished tasks"); // 3
}
executor.shutdownNow();
System.out.println("shutdown finished"); // 4
}
}
static class Task implements Runnable {
public void run() {
try {
int duration = 6;
System.out.println("Running Task!"); // 2
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出现在符合预期,无论程序在何处都应该相同 运行:命令行,IDE,...
Shutdown executor
Running Task!
cancel non-finished tasks
shutdown finished
java.lang.InterruptedException: sleep interrupted
注意:
java.lang.InterruptedException: sleep interrupted
的顺序可能仍然不同,因为它是由 Throwable.printStackTrace()
编写的,它依赖于 system.err
。
我正在尝试 运行 下面的并发代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws
InterruptedException {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
executor.submit(new Task());
System.out.println("Shutdown executor");
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
System.err.println("tasks interrupted");
} finally {
if (!executor.isTerminated()) {
System.err.println("cancel non-finished tasks");
}
executor.shutdownNow();
System.out.println("shutdown finished");
}
}
static class Task implements Runnable {
public void run() {
try {
int duration = 6;
System.out.println("Running Task!");
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出为:
Shutdown executor
Running Task!
shutdown finished
cancel non-finished tasks
java.lang.InterruptedException: sleep interrupted
根据输出,finally 块似乎被跳过,finally 块之后的代码先执行,然后再执行 finally 块。这是否与 try/catch 块完成后最终执行的代码的正常流程相矛盾?
编辑:已尝试
System.out.flush();
System.err.flush();
每次按照其中一项建议打印后,输出仍然相同。
编辑:
我正在使用在线编译器。
我想您希望这两个跟踪被颠倒,因为它们是以相反的顺序声明的:
shutdown finished
cancel non-finished tasks
我认为问题来自 System.err
和 System.out
的混合。
这些不是相同的流。所以它们的 flushing 和它们的 displaying 可能在不同的时间执行。
根据显示输出的 application/system(IDE、OS 命令行、在线 compiler/executor),至少有两件事可能会导致排序问题:
- 这些流的 autoflush 可能启用或未启用
- application/system 的 "output/console" 中这两个流之间的跟踪显示顺序可能不同步。
作为根据时间线显示输出的解决方法:
在每次
print()
调用后刷新流(System.out.flush()
和System.err.flush()
)。
它可能有效,但不能保证 application/system 写入输出可能不会通过时间线同步这两个流的显示。尽量仅使用
System.out
,仅在程序将退出的错误情况下使用System.err
。 它将减少交错的可能性。如果最后一个想法不合适,因为清楚地区分两种输出很重要,请使用允许精确跟踪信息的日志库(Logback 或 Log4j2,最好在 facade 中带有 SLF4J) (日期、时间、严重级别...)并按照程序流时间线的实际顺序阅读它们。
这是仅使用 System.out
的相同代码:
我为输出的预期顺序添加了 //1
、//2
、...注释。
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
executor.submit(new Task());
System.out.println("Shutdown executor"); // 1
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
System.out.println("tasks interrupted"); // not invoked because caught in Task.run()
} finally {
if (!executor.isTerminated()) {
System.out.println("cancel non-finished tasks"); // 3
}
executor.shutdownNow();
System.out.println("shutdown finished"); // 4
}
}
static class Task implements Runnable {
public void run() {
try {
int duration = 6;
System.out.println("Running Task!"); // 2
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出现在符合预期,无论程序在何处都应该相同 运行:命令行,IDE,...
Shutdown executor
Running Task!
cancel non-finished tasks
shutdown finished
java.lang.InterruptedException: sleep interrupted
注意:
java.lang.InterruptedException: sleep interrupted
的顺序可能仍然不同,因为它是由 Throwable.printStackTrace()
编写的,它依赖于 system.err
。