![](/img/trans.png)
[英]Dealing with end of 'file' using BufferedReader.read()
[英]BufferedReader.read() eating 100% of CPU
我有一个 JAVA 游戏服务器,每个 TCP 连接使用 1 个线程。 (我知道这很糟糕,但我现在必须保持这种状态)。 在(3.2Ghz 6cor x2 机器,24GB RAM,windows server 2003 64bits)上,这是一段代码:
public void run()
{
try
{
String packet = "";
char charCur[] = new char[1];
while(_in.read(charCur, 0, 1)!=-1 && Server.isRunning)
{
if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r')
{
packet += charCur[0];
}else if(!packet.isEmpty())
{
parsePlayerPacket(packet);
packet = "";
}
}
}catch(Exception e)
{
e.printStackTrace();
}
finally
{
try{
kickPlayer();
}catch(Exception e){e.printStackTrace();};
Server.removeIp(_ip);
}
}
在大约 12 小时或更长时间的服务器正常运行时间(并且连接了大约 3.000 个玩家)之后,服务器开始消耗 100% 的所有 12 个 CPU,直到我手动重新启动 JAVA 应用程序。 所以游戏开始非常糟糕,我的球员开始抱怨。
我试过分析应用程序,这是我想出的:
所以我猜测问题来自这里:
while(_in.read(charCur, 0, 1)!=-1 && Server.isRunning)
知道变量“_in”是套接字输入的读取器:(_in = new BufferedReader(new InputStreamReader(_socket.getInputStream())))。
为什么 _in.read() 在长时间的服务器正常运行后占用这么多 CPU?
我试过放一个 Thread.sleep(1); 在 While 循环中还有更多,但没有做任何事情,我猜问题出在 BufferedReader.read() 方法内部。
有没有人知道是什么导致了这个? 以及如何修复它?
这是您上一个问题的重复: 我的代码中某处的无限循环。 请不要打开新问题,而是使用编辑功能。
话虽如此,3000 个线程肯定很多,而且很可能会导致过多的上下文切换。 考虑在 Java 中使用非阻塞 IO 设施,而不是为每个连接启动一个新线程。 示例可以在这里找到: http : //download.oracle.com/javase/1.4.2/docs/guide/nio/example/index.html
我不知道为什么调用很慢,但我永远不会在紧密循环中一次读取一个字节。 谁知道内部函数有什么样的开销。
我会读取流中当前可用的所有数据并对其进行解析。 这将需要一个缓冲区和一些额外的簿记,但无论如何比从流中逐字节读取要快。
我也遇到了同样的问题,我也尝试了很多解决方案,但read(byte)没有运气。 但是当我尝试使用readLine() 时,它运行良好。 @Reacen您是否找到了任何其他答案,也请告诉我。
public void run() {
try {
InputStream input = clientSocket.getInputStream();
BufferedReader bf = new BufferedReader(new InputStreamReader(input));
while (isRunning) {
if (mainServer.isStopped()) {
disconnect();
}
if (clientSocket.isClosed()) {
isRunning = false;
break;
}
// New Code Receive commands from device
String result = null;
try {
result = bf.readLine();
if (result == null) {
disconnect();
} else {
Pattern pattern = Pattern.compile("(?<=\\[).*(?=\\])");
Matcher matcher = pattern.matcher(result);
if (matcher.find()) {
result = matcher.group(0);
}
}
} catch (SocketTimeoutException e) {
logger.debug("Socket Read Timeout: " + remoteAddress);
} catch (SocketException e) {
isRunning = false;
break;
}
if (result == null || result.trim().length() == 0) {
continue;
}
“每个 TCP 连接 1 个线程”“连接了大约 3.000 个玩家”
= 3.000 个线程?!
我的猜测:一次可以重复复制一个字节的最大线程数约为 3.000。 这听起来并不奇怪。
解决方案:减少线程并一次性读取更多字节。
您可以使用 executorService。 javadoc中有一个简单的例子: http : //download.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html
看起来您也从未关闭过 BufferedReader,除非您在 kickPlayer() 方法中尝试它。
每个读者的寿命可能比您意识到的要长得多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.