Java BufferedReader.readLine()有时会挂起
在我的应用程序中,有一个单独的线程,每分钟由ScheduledExecutorService.scheduleAtFixedRate()运行,它解析来自多个网站的rss提要。我正在使用ApacheHttpClient来接收xml 示例代码:Java BufferedReader.readLine()有时会挂起,java,apache,rss,httpclient,bufferedreader,Java,Apache,Rss,Httpclient,Bufferedreader,在我的应用程序中,有一个单独的线程,每分钟由ScheduledExecutorService.scheduleAtFixedRate()运行,它解析来自多个网站的rss提要。我正在使用ApacheHttpClient来接收xml 示例代码: InputStream inputStream = HTTPClient.get(url); String xml = inputStreamToString(inputStream, encoding, websiteName); public
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.1200 OK
编辑
我刚刚发现当挂起发生时,bufferedReader.ready()
实际上是true
编辑2
BufferedReader.read()
也会挂起。奇怪的是,挂起只发生在处理一个单一的网站,它的发生是绝对随机的。应用程序可以工作15个小时,收到数百个无问题的响应,或者在启动后10分钟内挂起。我已经开始将每个更新的所有字符写入单独的文件,并发现没有什么特别的事情发生。XML读取只是在文档中间永久停止,最后的字符是“代码> P dir=“LTR”和G < /代码>。更新了代码
另外,值得一提的是,不可能有任何未处理的异常,因为在我的ScheduledExecutorService.scheduleAtFixedRate()的最高级别上,我可以捕获Throwable
,并打印它的stackTrace。ready()
方法返回true
告诉您有可读取的字符。问题是readLine()
阻塞,直到它在输入中找到行的结尾
公共字符串读取行()
抛出IOException
读一行文字。一条线路被视为由任何一条线路终止
换行符('\n')、回车符('\r')或回车符的
紧接着是换行符
当您从流中读取数据时,无法保证数据将从行边界进入,因此readLine()
调用将阻塞
您可以使用不会阻塞的read
方法,但您必须自己检查EOL
公共整数读取(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,则表示
文件结尾,然后此方法返回-1。否则,此方法返回
实际读取的字符数
此外,您还必须根据读取的字符重建行。一次读取整行内容并不方便,但必须这样做。编码有问题吗?所以readLine()
无法识别EOL。@我不这么认为。EOL是标准的。如果readLine无法识别EOL,它将永远保持读取,并且您将遇到更大的问题,因为line变量将占用大量内存,并且字符串中以垃圾结尾。将代码更改为,而((letter=bufferedReader.read())!=-1)
,看起来它现在工作正常。谢天谢地,我真的不需要把线分开。天哪,它还是会不时冻结。有时看起来像是bufferedReader.read()
从不等于-1
。可能是什么情况?@DaSH你能发布你的更新代码吗-1应该表示EOF,但由于您不是从实际文件读取EOF,因此EOF的含义有所不同。至少你应该得到一个例外。它会永远被阻塞还是在一段时间后继续?