解决方案一:定时运行:如果希望某个方法在指定时间后返回或抛出异常,请使用以下方法在后台线程上执行该方法,同时等待它完成:
public static void timedRun(Runnable r, long timeout, TimeUnit unit)
throws InterruptedException, TimeoutException {
Future<?> task = executor.submit(r);
try {
task.get(timeout, unit);
} catch (ExecutionException e) {
throw launderThrowable(e.getCause());
} finally {
task.cancel(true);
}
}
private static RuntimeException launderThrowable(Throwable t) {
if (t instanceof RuntimeException) return (RuntimeException)t;
else if (t instanceof Error) throw (Error)t;
else throw new IllegalStateException("Not unchecked", t);
}
(来源:Goetz, Brian, Bloch, Joshua, Bowbeer, Joseph, Lea, Doug, Holmes, David and Peierls, Tim. Java Concurrency in Practice. : Addison-Wesley Longman, Amsterdam, 2006. Listing 5.13 and 7.10)
对于executor,您可以使用Executor.newSingleThreadExecutor() 创建一个新的,或重复使用现有的。
但请注意:虽然该方法保证在指定超时后返回或抛出异常,但不能保证runnable真的会停止!它会中断正在执行的线程,但如果 runnable 对线程中断没有反应(例如,通过内部检查 Thread.interrupted()),它可能会继续在后台运行 - 可能永远 - 占用一个线程!但至少它不会阻塞。
解决方案 2:使用自定义线程定时运行: 如果除了线程中断之外还有其他可能取消您的方法调用,您仍然可以使用上述方法,但是您必须使用 @987654327 @ 使用自定义 ThreadFactory 创建一个特殊的 Thread 实例,并覆盖 interrupt 方法:
Executor executor = Executor.newSingleThreadExecutor(r -> new WsdlThread(r));
public class WsdlThread extends Thread {
public WsdlThread(Runnable r) { super(r); }
public void interrupt() {
try {
// TODO: do something that will interrupt the wsdl call
// e.g. close connection to server, etc.
// example: ((WsdlRunnable)r).getWsdlConnection().close();
} finally {
super.interrupt();
}
}
}
如果这也不可能,并且Thread.stop() 也不起作用,那么最后一个解决方案可能会起作用:
解决方案 3:在另一个 JVM 中启动不可取消的调用:
使用Runtime.exec 启动另一个JVM 并在那里执行方法调用(有关如何执行此操作的更多信息,请参阅Executing a Java application in a separate process)。 Runtime.exec 会返回一个Process 对象,代表正在运行的进程。
您可以通过调用destroy() 或destroyForcibly() 来杀死它。