问题描述
上下文:
我在 java 中有一个 cmd 应用程序,它被编写为在不同的服务器上以对等模式工作。一旦服务器启动,所有其他实例必须停止。所以我写了一段代码,它运行在一个低优先级的线程中并监控一个 AtomicBoolean 值 autoClose
,每当 autoClose 设置为 true 时,线程将关闭应用程序。 (P.S.:我不想手动添加close,因为应用程序有2个主要的高优先级线程和许多临时的普通优先级线程)
代码如下:
/**
* Watches autoClose boolean value and closes the connector once it is true
* <p>
* This is a very low priority thread which continuously monitors autoClose
*/
protected void watchAndClose() {
Thread watchAutoClose = new Thread(() -> {
while (true) {
if (autoClose.get()) {
close();
// wait till closing is successful
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException ignored) {
// I want instance of thread watchAutoClose so I can call this
// watchAutoClose.interrupt();
}
if (!component.getStatus()) setAutoClose(false);
}
}
});
watchAutoClose.setPriority(Thread.MIN_PRIORITY);
watchAutoClose.start();
}
问题:
SonarLint 说我不能将 InterruptedException 部分留空。我必须再次抛出它或调用 thatThread.interrupt()
。
那我该怎么做呢?我想要该线程内的线程 watchAutoClose
实例,以便我可以调用 watchAutoClose.interrupt()
。我试过 Thread.currentThread()
但我担心有这么多线程,当前正在执行的线程不会是这个线程。 (即,JVM 有可能在位于 catch 子句中并调用 Thread.currentThread()
时选择切换到另一个线程,因此此时当前线程将是另一个线程我会打断另一个线程...如果我太担心或者我的概念完全错误,请纠正我。)
或者我应该完全忽略警告并离开 catch 块?
解决方法
首先,不清楚为什么您认为等待一秒钟是必要的。到 close()
方法返回时,close()
方法已经完成。另一方面,如果 close()
确实触发了一些异步操作,则无法保证等待一秒钟就足以完成。
此外,解决您的字面问题,Thread.currentThread()
始终返回调用线程的实例。线程不可能在不处于运行状态的情况下执行该方法。当任务切换发生时,线程根本无法读取引用,直到再次获得 CPU 时间。除此之外,由于规范说这个方法返回代表调用者的 Thread
实例,环境必须确保这个属性,不管它如何实现它。即使在不同的 CPU 内核上,多个线程真正同时调用此方法也能正常工作。
所以,不管等待一秒钟的方法有多么可疑,像处理中断一样
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
是一种有效的方法。
但是你也可以用
替换这个代码LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
parkNanos
方法将在中断时静默返回,使调用线程处于中断状态。因此,它与捕获 InterruptedException
并恢复中断状态具有相同的效果,但更简单且可能更高效,因为不需要构造、抛出和捕获异常。
另一点是,当变量为 false 时,您正在对消耗 CPU 周期的原子变量创建轮询循环,这是不鼓励的,即使您给线程一个低优先级。