我有一个Java函数。它通常在完成任务后返回一个值。但是,在某些情况下它什么都不返回。我创建了一个runnable并将此函数作为一个线程运行。但是,由于它没有返回值,因此尽管它完成了任务,但它并没有完成。该进程保持活动状态,因为它等待返回值。有没有办法在触发或超时后终止该线程? Stop()或Destroy()不起作用。在调试期间,线程被视为活着,我希望它被bi删除/删除
Runnable runnable = new Runnable() {
@Override
public void run() {
int stat = RunMyFunction();
}
};
Thread thread = new Thread(runnable);
thread.start();
答案 0 :(得分:1)
Java不支持通过java.lang.Thread上的任何方法杀死线程。
stop()和destroy()乍一看看起来很有希望,但它们都被弃用了。
销毁状态的文档:
此方法最初设计用于在不进行任何清理的情况下销毁此线程。但是,该方法从未实施过。如果要实施,那将是容易死锁的
并停止:
这种方法本质上是不安全的。使用Thread.stop停止一个线程会导致它解锁它已锁定的所有监视器(这是未经检查的ThreadDeath异常向上传播的自然结果)。如果先前受这些监视器保护的任何对象处于不一致状态,则受损对象对其他线程可见,可能导致任意行为。
因此,当文档说“弃用”时,它真正意味着它们被破坏了,绝对不能被使用!?! Java API设计人员为其API的向后兼容性做了大量工作,其他语言将删除这些方法Sun决定将它们作为内部指南(正确或错误地)保留,不允许删除公共api方法。 / p>
所以,问题仍然存在。如何让一个线程退出另一个线程?遗憾的是,人们必须以某种方式来轮询退出变量。这可以是自定义变量,也可以是java.lang.Thread中的标准标志,可通过' interrupted()'访问。使用interrupted()的优点是其他Java API(如IO)在阻止API调用期间支持此标志,并将退出抛出InterruptedException。调用interrupt()的检测不是立即的,因为它设置了一个标志并依赖于Thread来在将来的某个时刻轮询该变量。
Oracle提供了有关如何使用中断here进行编码的教程。
答案 1 :(得分:1)
你遇到的真正问题是RunMyFunction
有时永远不会终止。正如其他人已经说过的那样,杀死一个线程并不是用Java编写的,因此没有好办法。相反,您应该说明为什么要调用可能非终止的方法。这看起来像代码味道。执行以下操作:
如果您是RunMyFunction
的作者,请确保它始终终止或它可能会被中断。您可以通过Thread.currentThread().isInterrupted()
和throw
InterruptedException
来检查void run(){
while(...){ // this loop sometimes runs forever
if(Thread.currentThread().isInterrupted())
throw new InterruptedException(); // Now, we can "kill" this thread here
}
}
。 E.g:
{{1}}
答案 2 :(得分:0)
使用ExecuterService可以指定超时。
ExecutorService executor = Executors.newFixedThreadPool(1);
List<Callable<String>> tasks = new ArrayList<Callable<String>>();
tasks.add(new Callable<String>() {
@Override
public String call() throws Exception {
int stat = RunMyFunction();
return "Execution Finished";
}
});
new Thread(new Runnable() {
@Override
public void run() {
try {
executor.invokeAll(tasks, 10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
invokeAll(...)是一个阻塞调用,所以我添加了一个新线程。
答案 3 :(得分:0)
解决方案1:定时运行:如果希望方法在指定的时间后返回或抛出异常,请使用以下方法在后台线程上等待它时执行该方法完成:
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);
}
对于executor
,您可以使用Executor.newSingleThreadExecutor()
创建一个新的,或重复使用现有的。{/ p>
但要注意:虽然这种方法可以保证在指定的超时后返回或抛出异常,但无法保证runnable真的会停止!它会中断正在执行的线程,但是如果runnable没有对线程中断做出反应(例如通过内部检查Thread.interrupted()
),它可能会继续在后台运行 - 可能永远 - 占用一个线程!但至少它不会阻止。
解决方案2:使用自定义线程定时运行:如果在线程中断后有可能取消您的方法调用,您仍然可以使用上述方法,但是您必须使用{{ 1}}使用自定义Executor
创建一个带有重写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();
}
}
}
也不起作用,那么最后一个解决方案可能会有效:
解决方案3:在另一个JVM中启动不可取消的调用:
使用Thread.stop()
启动另一个JVM并在那里执行方法调用(有关如何执行此操作的详细信息,请参阅Executing a Java application in a separate process)。 Runtime.exec
将返回一个Runtime.exec
对象,表示正在运行的进程。
您可以通过拨打Process
或destroy()
来杀死它。