2017-04-07 45 views
1

在我的应用程序中,有一个单独的线程,每分钟运行ScheduledExecutorService.scheduleAtFixedRate(),它解析来自多个网站的rss提要。我使用Apache HttpClient来接收XML。BufferedReader.readLine()有时会挂起

示例代码:

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.readLine()上?

如果它的事项,response.getStatusLine().toString()总是返回HTTP/1.1 200 OK

编辑

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

编辑2

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

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

回答

1

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

公共字符串的readLine() 抛出IOException异常

读取一行文本。一条线被换行符('\ n'),回车符('\ r')或回车符 中的任意一个 被认为是由一个换行符紧接。

当您从流读取时,不能保证数据将在行边界处出现,因此readLine()调用块。

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

公共INT读(烧焦[] CBUF,整数关,INT LEN)抛出IOException异常

字符读入阵列的一部分。

此方法实现Reader类的相应读取方法的一般合同。作为额外的便利,它通过反复调用基础流的读取方法 ,尝试 读取尽可能多的字符。这种迭代的读取继续进行,直到满足下列条件 一个为真:

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第一读取以指示 文件结束-则此方法返回-1。否则,此方法返回实际读取的字符数 。

此外,您将不得不重建从读取的字符行。一次读完整条线不是很方便,但它是必须完成的方式。

+0

难道是编码问题吗?所以'readLine()'不能识别EOL。 – DaSH

+0

@DaSH我不这么认为。 EOL是标准的。如果readLine没有识别EOL,它会一直读取,并且你会遇到更大的问题,因为行变量会使用大量内存,并且会以字符串中的垃圾结束。 – whbogado

+0

将代码更改为'while((letter = bufferedReader.read())!= -1)',看起来好像现在工作正常。谢天谢地,我不需要分开线路。 – DaSH