在java类中,我有一个有时需要很长时间才能执行的方法。也许它挂在那个方法流程中。我想要的是如果方法没有在特定时间内完成,程序应退出该方法并继续其余的流程。
请让我知道有没有办法处理这种情况。
答案 0 :(得分:7)
您必须使用线程才能实现此目的。线程没有害处:)下面的例子运行一段代码10秒然后结束它。
public class Test {
public static void main(String args[])
throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("0");
method();
}
});
thread.start();
long endTimeMillis = System.currentTimeMillis() + 10000;
while (thread.isAlive()) {
if (System.currentTimeMillis() > endTimeMillis) {
System.out.println("1");
break;
}
try {
System.out.println("2");
Thread.sleep(500);
}
catch (InterruptedException t) {}
}
}
static void method() {
long endTimeMillis = System.currentTimeMillis() + 10000;
while (true) {
// method logic
System.out.println("3");
if (System.currentTimeMillis() > endTimeMillis) {
// do some clean-up
System.out.println("4");
return;
}
}
}
}
答案 1 :(得分:1)
在不同的线程中执行该方法,您可以随时结束一个线程。
答案 2 :(得分:0)
基于上面的小贴士,我尝试创造一个美化的春豆。
此类执行程序在有限的 runtimeInMs 中运行传递的 restrictedRuntimeTask 。 如果任务在其时间限制内完成,则调用者将继续正常执行。
如果 limitedRuntimeTask 无法在定义的 runtimeInMs 中完成, 调用者将收到线程执行回来。如果定义了timeBreachedTask, 它将在返回调用者之前执行。
public class LimitedRuntimeExecutorImpl {
public void runTaskInLessThanGivenMs(int runtimeInMs, final Callable limitedRuntimeTask, final Callable timeBreachedTask) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
LOGGER.info("Started limitedRuntimeTask");
limitedRuntimeTask.call();
LOGGER.info("Finished limitedRuntimeTask in time");
} catch (Exception e) {
LOGGER.error("LimitedRuntimeTask exception", e);
}
}
});
thread.start();
long endTimeMillis = System.currentTimeMillis() + runtimeInMs;
while (thread.isAlive()) {
if (System.currentTimeMillis() > endTimeMillis) {
LOGGER.warn("LmitedRuntimeTask did not finish in time (" + runtimeInMs + ")ms. It will run in vain.");
if(timeBreachedTask != null ){
try {
LOGGER.info("Executing timeBreachedTask");
timeBreachedTask.call();
LOGGER.info("Finished timeBreachedTask");
} catch (Exception e) {
LOGGER.error("timeBreachedTask exception", e);
}
}
return;
}
try {
Thread.sleep(10);
}
catch (InterruptedException t) {}
}
}
}
答案 3 :(得分:0)
我觉得接受答案的方法有点过时了。使用Java8,可以更简单地完成它。
说,你有一个方法
MyResult conjureResult(String param) throws MyException { ... }
然后你可以这样做(继续阅读,这只是为了显示方法):
private final ExecutorService timeoutExecutorService = Executors.newSingleThreadExecutor();
MyResult conjureResultWithTimeout(String param, int timeoutMs) throws Exception {
Future<MyResult> future = timeoutExecutorService.submit(() -> conjureResult(param));
return future.get(timeoutMs, TimeUnit.MILLISECONDS);
}
当然,抛出异常是坏的,这是正确的扩展版本,并且有正确的错误处理,但我建议你仔细检查一下,你可能想要做一些不同的事情(记录,在扩展结果中返回超时等):
private final ExecutorService timeoutExecutorService = Executors.newSingleThreadExecutor();
MyResult conjureResultWithTimeout(String param, int timeoutMs) throws MyException {
Future<MyResult> future = timeoutExecutorService.submit(() -> conjureResult(param));
try {
return future.get(timeoutMs, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
//something interrupted, probably your service is shutting down
Thread.currentThread().interrupt();
throw new RuntimeException(e);
} catch (ExecutionException e) {
//error happened while executing conjureResult() - handle it
if (e.getCause() instanceof MyException) {
throw (MyException)e.getCause();
} else {
throw new RuntimeException(e);
}
} catch (TimeoutException e) {
//timeout expired, you may want to do something else here
throw new RuntimeException(e);
}
}