我正在尝试运行以下并发代码:
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块。这是否与在try / catch块完成后最终执行的代码的正常流程相矛盾?
编辑:尝试
System.out.flush();
System.err.flush();
每次打印后按照其中一个建议但仍然是相同的输出。
编辑:
我正在使用在线编译器。
答案 0 :(得分:3)
我认为您希望这两条轨迹相反,因为它们是以相反的顺序声明的:
关闭完成
取消未完成的任务
我认为问题来自于System.err
和System.out
的混合
这些不是相同的流。因此,他们的刷新和他们的显示可以在不同的时间执行。
根据显示输出的应用程序/系统(IDE,OS命令行,在线编译器/执行程序),至少有两件事可能会产生排序问题:
根据时间线显示输出的解决方法:
在每次System.out.flush()
调用后刷新流(System.err.flush()
和print()
)。
它可能有效但不能保证作为写入输出的应用程序/系统可能无法通过时间线同步显示这两个流。
尝试仅使用System.out
并仅在程序退出的错误情况下使用System.err
。
它将减少交错的可能性。
如果最后一个想法不合适,因为清楚地区分这两种输出很重要,使用一个日志库(Logback或Log4j2,最好是在外观中使用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,......
关闭执行程序
跑步任务!
取消未完成的任务
关闭完成
java.lang.InterruptedException:sleep interrupted
请注意:
java.lang.InterruptedException:sleep interrupted
可能仍然有所不同,因为Throwable.printStackTrace()
依据system.err
撰写。