我有以下代码:
private static final AtomicBoolean shutdown = new AtomicBoolean(false);
public static void main(final String... args) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
shutdown.set(true);
executorService.shutdown();
try {
executorService.awaitTermination(SHUTDOWN_TIMEOUT.getSeconds(), TimeUnit.SECONDS);
} catch (InterruptedException e) {
executorService.shutdownNow();
}
}));
executorService = Executors.newFixedThreadPool(2);
for (int i = 0; i < 2; i++) {
executorService.execute(create());
}
}
private static Runnable create() {
return new Runnable() {
@Override
public void run() {
while (!shutdown.get()) {
try {
Thread.sleep(5000);
System.out.println("Hatella" + Thread.currentThread().getName());
} catch (Throwable t) {
}
}
}
};
}
这段代码可以很好地工作,但是我想用更简单的方式编写这段代码,这样我就不必在每个while循环中检查shutdown标志的状态。不知道该怎么做才能解决此问题并实现相同的目的。
答案 0 :(得分:1)
shutdown()
仅会使ExecutorService
不接受更多任务,但是它将继续执行所有待处理的任务直到最后。由于您实际上想停止执行任务,因此应首先使用shutdownNow()
,它会发送一个中断信号。
public static void main(final String... args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
executorService.shutdownNow();
try {
executorService.awaitTermination(
SHUTDOWN_TIMEOUT.getSeconds(),TimeUnit.SECONDS);
} catch (InterruptedException e) {}
}));
for (int i = 0; i < 2; i++) {
executorService.execute(create());
}
}
private static Runnable create() {
return () -> {
while(!Thread.interrupted()) {
try {
Thread.sleep(5000);
System.out.println("Hatella" + Thread.currentThread().getName());
}
catch(InterruptedException ex) {
break;
}
catch (Throwable t) {
}
}
System.out.println("thread exit " + Thread.currentThread().getName());
};
}
不仅可以通过Thread.interrupted()
查询中断标志,还可以使诸如Thread.sleep(…)
之类的阻塞操作提前终止,并通过InterruptedException
报告情况。在这两种情况下,当Thread.interrupted()
返回true
或引发InterruptedException
时,中断状态都会被重置,因此至关重要的是要么立即对其作出反应,要么记住您已收到它。因此,在上面的示例中,catch(InterruptedException ex)
包含一个break
,以结束循环。
但是如图所示,中断不会终止线程,但可以对其进行反应,例如在需要之前清理,然后退出。
请注意,当只有冗长的操作是阻止操作时,您根本不需要手动轮询中断状态,例如以下也可以工作:
private static Runnable create() {
return () -> {
while(true) {
try {
Thread.sleep(5000);
System.out.println("Hatella" + Thread.currentThread().getName());
}
catch(InterruptedException ex) {
System.out.println("got "+ex+", "+Thread.interrupted());
break;
}
catch (Throwable t) {
}
}
System.out.println("thread exit");
};
}
由于此代码不会通过Thread.interrupted()
来检查并重置中断状态,因此该信号将持续到下一次调用Thread.sleep
时为止,该调用将很快显示为立即响应,因为两次sleep
调用之间执行的代码很短。
答案 1 :(得分:0)
A)参见Turning an ExecutorService to daemon in Java。守护程序线程将在技术上回答所陈述的问题(无需轮询“关闭”变量),但在任何有状态的上下文中都可能是 bad 想法,因为该线程将在操作过程中停止,而不会发出警告JVM(所有非守护进程线程完成后)。
executorService = Executors.newFixedThreadPool(2, r -> {
Thread t = Executors.defaultThreadFactory().newThread();
t.setDaemon(true);
return t;
});
B)现实世界中的另一种选择(空闲线程可能阻塞或休眠某物)是仅在shutdown
出现的InterruptedException
上检查executorService.shutdownNow()
< / p>