Java 一直锁定在从互联网收集信息的程序中

Java keeps locking up in program that gathers information from internet

我有一个 Java 程序正在从 Internet 收集信息。它使用 BufferedReader 和 URLConnection 每 3 秒从 Yahoo 检索一个 csv 文件。然后它使用 BufferedWriter 附加一个不同的 CSV 文件,其中包含重新格式化的数据。

大多数情况下会运行成功2-3天,但它似乎无缘无故地锁定。标准输出只是停止报告任何进展。

我以为我会通过每天 运行 修复它来修复它,但是有 3-4 天的一天它会在一天中的不同时间失败。它与 Internet 建立了大约 8400 个连接,每天总计约 8 MB。

下面的代码是从互联网上读取信息的代码。这是在一个方法中,该方法 returns 一个对象,该对象包含一个表示 ASCII 文件的字符串数组。

    BufferedReader br = null;
    String thisLine;
    try{
        URLConnection urlConn = url.openConnection();
        br = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
    }
    catch (IOException e) {
        System.err.println("Error: " + e);
    }
    try{
        while((thisLine = br.readLine()) != null){
            lines.add(thisLine);
            size++;
        }
    }
    catch(IOException e){}

这不是多线程应用程序。

所以我一直在思考可能出了什么问题,以下是我的猜测:

  1. 我对 URLConnection 做了一些错误,导致它挂起。 (我所做的与 URLConnection 相关的所有事情都在我的编码中)
  2. 我有一些内存问题,我使用了足够多的内存来移动我有一个对程序来说是致命的错误(这是 运行 在 PC 上,而不是在带有 ECC RAM 的服务器上) .我不知道这样做的可行性。
  3. 我正在将我的数据与对日历的调用同步。我不知道每分钟调用 Calendar 60 次是否会对 JVM 产生不良影响。
  4. 文件锁和重复附加可能锁定 JVM 的文件存在一些不稳定性(参见下面的代码)
  5. 我没有关闭我不知道要关闭的东西。

程序存储数据并每 30 秒附加一次输出文件:

/**
 * Writes a file at the path denoted by fileName.  This will be an ASCII file.
 * @param fileName The path to write the file to
 */
public void appendFile(String fileName){
    try {
        //if()
        BufferedWriter b = Files.newBufferedWriter(new File(fileName).toPath(), Charset.defaultCharset(),StandardOpenOption.APPEND);
        for(int i = 0; i < size; i++){
            b.write(lines.get(i));
            b.newLine();
        }
        b.close();
    } 
    catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

一些其他注意事项:

此程序 运行 处于最佳状态。我想每秒收集一次数据,但它跟不上。这似乎受互联网连接的限制。

我没有任何记忆问题。我看一下我的记忆,好像没有什么漏洞。

无论我 运行 作为应用程序,运行 在 Eclipse 中,还是 运行 作为系统任务 (Windows 7),都会发生同样的事情。

如有任何帮助,我们将不胜感激。上面所有这些想法都是我一直在集思广益的事情,所以如果其中一个看起来真的很愚蠢,我理解。此外,任何关于探索该问题的建议都会很棒。我有一些使用 Eclipse 调试器的经验,但像这样的东西,在启动后 6 小时挂起(当我在工作时)对我来说有点难以探测。我从来没有成功地使用调试器来评估挂断,只有抛出 RuntimeException 的错误,或者使用断点。

既不是锁定也不是冻结。它正在阻塞, 试图从无响应的服务器读取数据。

解决方法是在 HttpURLConnection 上设置读取超时,捕获结果 SocketTimeoutException,并适当地处理它,无论这对您的应用程序意味着什么。

注意您发布的代码应该全部在一个 try/catch 结构中。依赖于 try 块中代码成功的代码应该在 try 块的一侧。并且不要忽略异常。

我能够通过在单独的线程中启动 URLConnections 来解决这个问题。然后,如果连接命中无响应的服务器(或者如果有任何问题),下一个线程仍会被触发。这不是最优雅的解决方案,但它确实有效。

每个线程调用主class持有的数据结构,并将下载的数据放在那里。然后,当数据超过设定点时,数据会被排序并附加到 CSV 文件中。我打算添加一些代码,以防万一它可以帮助别人。

我尝试设置超时,但没有成功。它仍然会锁定。真正的问题是它每 12 小时失败一次,而我 运行 一次失败 8 小时,因此很难调试(这需要数周时间,日历时间)。无论如何,线程也解决了延迟以下数据点的任何问题,超时不会解决,因为我可能会将超时设置为比我检索数据的频率更长的时间。

我的两分钱...

  1. 您要关闭 BufferedReader 吗?它在发布的代码中没有看到。
  2. 我猜 3 秒对于雅虎服务器来说太频繁了,无法识别自动请求并阻止此类请求,除非它是开放的 API/您被授权执行此类请求。