【问题标题】:BufferedReader.readLine() hangs sometimesBufferedReader.readLine() 有时会挂起
【发布时间】:2017-09-02 21:54:16
【问题描述】:

在我的应用程序中,有一个单独的线程,由 ScheduledExecutorService.scheduleAtFixedRate() 每分钟运行一次,它解析来自多个网站的 rss 提要。我正在使用 Apache HttpClient 来接收 xml。

示例代码:

InputStream inputStream = HTTPClient.get(url);    
String xml = inputStreamToString(inputStream, encoding, websiteName);

public static String inputStreamToString(InputStream inputStream, String encoding, String websiteName) 
{

    BufferedReader bufferedReader = null;
    PrintWriter printWriter = null;
    StringBuilder stringBuilder = new StringBuilder();

    int letter;
    try 
    {
        bufferedReader = new BufferedReader(new InputStreamReader(inputStream, encoding));
        printWriter = new PrintWriter(new File("src/doclog/" 
                + websiteName + "_" 
                + new SimpleDateFormat("MM_dd_yyyy_hh_mm_ss").format(new Date(System.currentTimeMillis())) 
                + "_" + encoding + ".txt"), encoding);
        while((letter = bufferedReader.read()) != -1) 
        {
            char character = (char) letter;
            printWriter.print(character);               
            stringBuilder.append(character);
        }
    } 
    catch(IOException e) 
    {
        throw new RuntimeException(e);
    } 
    finally
    {
        try 
        {
            if(bufferedReader != null) 
            {
                bufferedReader.close();
            }
            if(printWriter != null) 
            {
                printWriter.close();
            }
        } 
        catch(IOException e) 
        {
            e.printStackTrace();
        }
    }
    System.out.println("String built");
    return stringBuilder.toString();
}

和 HTTPClient 类:

public class HTTPClient 
{
   private static final HttpClient CLIENT = HttpClientBuilder.create().build(); 

   public static InputStream get(String url)
   {    
       try
       {
           HttpGet request = new HttpGet(url);  
           HttpResponse response = CLIENT.execute(request);
           System.out.println("Response Code: " + response.getStatusLine().toString()); 
           return response.getEntity().getContent();
       }
       catch(IOException | IllegalArgumentException e)
       {
           throw new RuntimeException(e);
       }
   }
}

正如标题所说,有时bufferedReader.readLine() 有可能永远挂起。我已经看到有关此主题的另一个答案,他们建议检查bufferedReader.ready() 是否返回true。问题是有些网站在处理它们时总是会在bufferedReader.ready() 中返回false,但是它们解析得很好。

如何防止我的线程挂在 bufferedReader.readLine() 上?

如果重要,response.getStatusLine().toString() 总是返回 HTTP/1.1 200 OK

编辑

我刚刚发现 bufferedReader.ready() 在挂起时实际上是 true

编辑 2

BufferedReader.read() 也挂起。奇怪的是,只有在处理一个网站时才会发生挂起,而且它的发生是绝对随机的。应用程序要么工作 15 小时,收到数百个无问题的响应,要么在启动后 10 分钟内挂起。我已经开始将每个更新的所有字符写入单独的文件中,并发现并没有真正发生什么特别的事情。 Xml 读取在文档中间永远停止,最后一个字符是<p dir="ltr"&g。更新了代码。

另外,值得注意的是,不能有任何未处理的异常,因为在我的ScheduledExecutorService.scheduleAtFixedRate() runnable 的最高级别,我捕获了Throwable,并打印它的stackTrace。

【问题讨论】:

    标签: java apache rss httpclient bufferedreader


    【解决方案1】:

    ready() 方法返回 true 告诉您有可供读取的字符。问题是readLine() 会阻塞,直到它在输入中找到行尾。

    公共字符串 readLine() 抛出 IOException

    读取一行文本。一条线被认为被任何人终止 换行符 ('\n')、回车符 ('\r') 或回车符 紧接着是换行符。

    当您从流中读取数据时,无法保证数据会进入行边界,因此 readLine() 调用会阻塞。

    您可以使用不会阻塞的read 方法,但您必须自己检查EOL。

    public int read(char[] cbuf, int off, int len) 抛出 IOException

    将字符读入数组的一部分。

    该方法实现了对应读的通用合约 Reader 类的方法。作为额外的便利,它尝试 通过重复调用 read 来读取尽可能多的字符 底层流的方法。这种迭代读取一直持续到 以下条件之一为真:

    The specified number of characters have been read,
    The read method of the underlying stream returns -1, indicating end-of-file, or
    The ready method of the underlying stream returns false, indicating that further input requests would block. 
    

    如果对底层流的第一次读取返回 -1 表示 end-of-file 然后这个方法返回 -1。否则此方法返回 实际读取的字符数。

    您还必须根据读取的字符重建该行。一次阅读整行并不方便,但必须这样做。

    【讨论】:

    • 会不会是编码的问题?所以readLine() 无法识别 EOL。
    • @DaSH 我不这么认为。 EOL 是标准的。如果 readLine 无法识别 EOL,它会一直读取,并且您会遇到更大的问题,因为 line 变量会使用大量内存,并且您会以字符串中的垃圾结尾。
    • 将代码更改为while((letter = bufferedReader.read()) != -1) ,看起来现在可以正常工作了。谢天谢地,我真的不需要分开行。
    • 天哪,它仍然不时冻结。看起来有时bufferedReader.read() 永远不会等于-1。可能是什么情况?
    • @DaSH 你能发布你更新的代码吗? -1 应该表示 EOF,但由于您不是从实际文件中读取 EOF 意味着不同的东西。至少你应该得到一个例外。它是永远被阻止还是会在一段时间后继续?
    猜你喜欢
    • 2013-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 2014-04-07
    • 1970-01-01
    相关资源
    最近更新 更多