【问题标题】:How can I cancel a Task after a timeout?超时后如何取消任务?
【发布时间】:2014-06-04 00:53:05
【问题描述】:

我有一些 Task 执行了一个可能挂起的 I/O 阻塞操作(从 URL 获取文件)

task = new Task<List<WSDLOperation>>() {
            @Override
            protected List<WSDLOperation> call() {
                List<WSDLOperation> services = new ArrayList<>();
                try {
                    services = WSDLService.createService(wsdlURL).getOperations();
                } catch (Exception ex) {
                    LOG.log(Level.WARNING, "Can't reach {0}", wsdlURL);
                }
                return services;
            }
        };

    }

方法createService 可以永远等待而不会抛出任何Exception。 (我使用 Main 类中定义的全局 (static public)ExecutorService 执行任务。

【问题讨论】:

  • 看起来问题出在 createService 方法中。可以永远挂起的方法应该抛出中断的异常,否则很难杀死它(你总是可以调用 System.exit 这是一个不好的做法 - 它会杀死整个 jvm )。如果您还没有,请参阅stackoverflow.com/questions/671049/…
  • createService 是第三方方法,我无法控制它,有什么方法可以将Task 与一些超时相关联吗?
  • 你有api文档的链接吗?
  • Future 可能会对您有所帮助。见stackoverflow.com/questions/2275443/how-to-timeout-a-thread
  • 该操作似乎在长时间超时后触发了Exception

标签: java concurrency javafx javafx-8


【解决方案1】:

超时后如何使用future和取消任务:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class Test {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Task t = new Task();
        Future<String> future = executor.submit(t);

        try {
            System.out.println("Started..");
            System.out.println(future.get(5, TimeUnit.SECONDS)); // throws
                                                                    // TimeoutException
            System.out.println("Finished!");
        } catch (TimeoutException e) {
            future.cancel(true);
            System.out.println("Terminated!");
        }
    }
}

class Task implements Callable<String> {
    @Override
    public String call() throws Exception {
        for (int i = 0; i < 1000; i++) {
            Thread.sleep(1000);
            System.out.println("task running!");
        }
        return "Ready!";
    }
}

【讨论】:

  • 这里TimeoutException处理部分中的future.cancel(true)只会将未来线程的中断标志设置为true对吗?它不能保证未来实际上会停止并终止正在进行的任务。
【解决方案2】:

你使用的是ExecutorService,所以提交任务后就可以了:

ExecutorService executor = // ...  
Future<?> future = executor.submit(task);
future.get(5, TimeUnit.MINUTES); // timeout 5 mins

【讨论】:

  • 这仍然不会杀死任务本身。这只是意味着调用者放弃了阻塞get。如果createService 是可中断的,调用者可以尝试future.cancel(true),否则他们就不走运了。
  • javafx 线程上调用 future.get 会阻塞 UI。
猜你喜欢
  • 2014-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多