简体   繁体   English

在Java中,是否可以将方法执行一段时间,达到时间限制后停止?

[英]In Java, is it possible to execute a method for a period of time and stop after it reaches the time limit?

I have this code that downloads a web page:我有这个下载 web 页面的代码:

HttpURLConnection connection;

private String downloadContent() {
    InputStream content;
    Source parser;
    try {
        content = connection.getInputStream(); //<--here is the download
        parser = new Source(content);            
        content.close();
        return parser.toString();
    } catch (Exception e) {
        return null;
    }
}

While doing the download, I tried to get the amount of downloaded data, and if it reaches a limit, I stop the downloading, but I not found a way to do this.在进行下载时,我试图获取下载的数据量,如果达到限制,我会停止下载,但我没有找到这样做的方法。 If someone know how to do, please tell me.如果有人知道该怎么做,请告诉我。

Now I want to limit the download time.现在我想限制下载时间。 Example: if the download pass 20 seconds, I stop it.示例:如果下载通过 20 秒,我停止它。 I want to do this because my program it's an webcrawler and if by an error, it begins downloading a big file, it will stuck in the download, and is not this I want to do, so a filter in download by size is welcome, but as I don't know, a filter time will prevent this problem.我想这样做是因为我的程序是一个网络爬虫,如果出现错误,它开始下载一个大文件,它会卡在下载中,这不是我想做的,所以欢迎按大小过滤下载,但我不知道,过滤时间会阻止这个问题。

You can use AOP and a @Timeable annotation from jcabi-aspects (I'm a developer):您可以使用来自jcabi-aspects的 AOP 和@Timeable注释(我是开发人员):

@Timeable(limit = 1, unit = TimeUnit.SECONDS)
String downloadContent() {
  if (Thread.currentThread.isInterrupted()) {
    throw new IllegalStateException("time out");
  }
  // download
}

Pay attention that you should check for isInterrupted() regularly and throw an exception when it is set to TRUE .请注意,您应该定期检查isInterrupted()并在设置为TRUE时抛出异常。 This is the only way to terminate a thread in Java.这是在 Java 中终止线程的唯一方法。

Also, for more detailed explanation, check this post: http://www.yegor256.com/2014/06/20/limit-method-execution-time.html另外,有关更详细的说明,请查看此帖子: http://www.yegor256.com/2014/06/20/limit-method-execution-time.html

The proper way to achieve this is the following:实现这一目标的正确方法如下:

public class TimeOut {

    public static class MyJob implements Callable<String> {

        @Override
        public String call() throws Exception {
            // Do something
            return "result";
        }

    }

    public static void main(String[] args) {

        Future<String> control
                = Executors.newSingleThreadExecutor().submit(new MyJob());

        try {

            String result = control.get(5, TimeUnit.SECONDS);

        } catch (TimeoutException ex) {

            // 5 seconds expired, we cancel the job !!!
            control.cancel(true);

        }
        catch (InterruptedException ex) {

        } catch (ExecutionException ex) {

        }

    }

}

There is a specified class java.util.Timer that is intended to do the tasks you required.You can reference the API for more detail.有一个指定的 class java.util.Timer用于执行您需要的任务。您可以参考 API 了解更多详细信息。

Life is messy.生活很混乱。 If you want to clean up after yourself, it takes some work.如果您想自己清理,则需要一些工作。

private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(20);
private String downloadContent() {
  connection.setConnectTimeout(TIMEOUT); /* Set connect timeout. */
  long start = System.nanoTime(); 
  final InputStream content;
  try {
    content = connection.getInputStream();
  } catch (IOException ex) { 
    return null;
  }
  /* Compute how much time we have left. */
  final long delay = TIMEOUT - 
    TimeUnit.NANOS.toMillis(System.nanoTime() - time); 
  if (delay < 1)
    return null;
  /* Start a thread that can close the stream asynchronously. */
  Thread killer = new Thread() {
    @Override
    public void run() {
      try {
        Thread.sleep(delay); /* Wait until time runs out or interrupted. */
      } catch (InterruptedException expected) { 
        Thread.currentThread().interrupt();
      }
      try {
        content.close();
      } catch (IOException ignore) {
        // Log this?
      }
    }
  };
  killer.start();
  try {
    String s = new Source(content).parser.toString();
    /* Task completed in time; clean up immediately. */
    killer.interrupt();
    return s;
  } catch (Exception e) {
    return null;
  }
}

You can't stop a running thread.您无法停止正在运行的线程。 What you can do, however:但是,您可以做什么:

1) Create a new thread and fetch the content from this thread. 1)创建一个新线程并从该线程中获取内容。 If the thread takes too long to answer, just go on and ignore its results.如果线程回答时间过长,只需打开 go 并忽略其结果。 Downside of this approach: the background thread will still download the big file.这种方法的缺点:后台线程仍然会下载大文件。

2) Use another HTTP connection API with more controls. 2) 使用另一个 HTTP 连接 API 具有更多控制。 I've used "Jakarta Commons HttpClient" a long time ago and was very pleased with its ability to timeout.我很久以前就使用过“Jakarta Commons HttpClient”,并且对它的超时能力非常满意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM