我想要中断一个线程,该线程在一个无限的while循环的每个增量中检查中断标志。退出循环的唯一方法是抛出InterruptedException。
在可中断线程执行的(不可访问的)代码中的某处,休眠操作声明了一个InterruptedException和一个catch块,其中异常被吞噬。不幸的是,在执行睡眠方法时,线程将被中断,从而导致中断标志被重置。在这种情况下,线程不会退出无限的while循环。
避免这种情况的最佳策略是什么?下面代码中的主线程在循环中调用interrupt,直到可中断线程不再活动为止。这是一个合理的策略吗?有什么替代方案吗?
public class InterruptableThreads extends Thread {
public static Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
try {
Thread.sleep(5000);
} catch (Exception e) {
System.out.println("Swallowing exception. Resetting interrupted flag");
}
System.out.println("t1 run");
}
} catch (InterruptedException e) {
System.err.println("t1 interrupted.");
}
}
});
public static void main(String[] args) throws InterruptedException {
t1.start();
Thread.sleep(4000);
while (t1.isAlive()) {
t1.interrupt();
}
t1.join(1000);
System.out.println("Finished!");
}
}发布于 2018-02-17 23:24:18
你提出的解决方案,包括循环直到线程死亡,应该可以工作。我不知道这是否可能,但您可能希望通过在该循环中包含join语句来避免主动旋转:
while (t1.isAlive()) {
t1.interrupt();
try {
t1.join(1000);
} catch(InterruptedException e) {
...
}
}另一种方法是将接受中断的代码的执行与可中断线程的主循环隔离开来:
public static Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> f = null;
try {
while (true) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
f = executor.submit(new Runnable() {
// swallowing code
});
try {
f.get();
} catch(CancellationException e) {
...
} catch(ExecutionException e) {
...
} // interrupted exceptions will be thrown from get() but not caught here
System.out.println("t1 run");
}
} catch (InterruptedException e) {
System.err.println("t1 interrupted.");
if (f != null) {
f.cancel(true);
}
} finally {
executor.shutdownNow();
}
}
});f.get()将使您有可能捕获t1的中断,而不管由executor服务启动的线程的状态如何,在该状态下,外部代码将被执行,并且可能处于“睡眠”状态。
但添加另一个线程会带来额外的复杂性和相关的风险。
发布于 2018-02-16 23:20:45
Brian Goetz在《实践中的Java并发》一书中概述了最佳策略。在内存中,您可以从catch块中重新中断线程,或者抛出异常。
另外,尽可能捕获最窄的异常,而不是Exception。
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
try {
Thread.sleep(5000);
} catch (InterrutedException e) { // <---- Narrow the scope here
System.out.println("Swallowing exception. Resetting interrupted flag");
Thread.currentThread().interrupt(); // <----- NEW
}https://stackoverflow.com/questions/48829549
复制相似问题