从套接字流中读取的线程需要更多 CPU 使用
Thread for reading from socket stream takes more CPU usage
在client socket中,我写了一个线程来不断读取socket的inputStream。这里我使用了一个while循环来无限读取。但是需要更多CPU;因此是否有可能减少 CPU。请添加您的建议。
也可以为 inputStream 添加侦听器。
线程代码:
public void run() {
while (!shutdown) {
try {
if(socketClient != null) {
String message = socketClient.getMessage();
logger.info ("Message size:" + message.length ());
if(!message.equals("EmptyString")) {
process(message);
}
}
} catch (Exception exception) {
logger.info("Unable to read the socket message" +exception);
}
}
}
SocketClient.java
public class SocketClient{
private volatile boolean isConnected;
private int port;
private int retryCount;
private long startTime;
private String hostName;
private DataInputStream input;
private DataOutputStream output;
private Socket socket;
public SocketClient(int port, String hostname) throws IOException {
this.port = port;
this.hostName = hostname;
establishConnection();
}
public void shutdown() {
try {
shutdown = true;
input.close();
output.close();
socket.close();
} catch (Exception e) {
logger.debug("Exception in shutdown:" + e.getMessage());
}
}
public String getMessage() {
BufferedReader reader = null;
try {
StringBuilder builder = new StringBuilder();
reader = new BufferedReader(new
InputStreamReader(tcpSocket.getInputStream()));
do {
builder.append(reader.readLine());
} while((reader.ready()));
if (builder.length() == 0)
return "EmptyString";
return builder.toString();
} catch (IOException e) {
return "EmptyString";
} finally {
try {
if(reader != null)
reader.close();
} catch(IOException e) {
logger.error("unable to close reader");
}
}
}
private void establishConnection() {
retryCount = 1;
startTime = System.currentTimeMillis();
while (!shutdown) {
try {
if(!isConnected) {
socket = new Socket(hostName,port);
socket.setKeepAlive(true);
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
isConnected = true;
shutdown = true;
}
} catch (Exception exception) {
isConnected = false;
sleepFewSeconds();
reconnectSocket();
}
}
}
private void reconnectSocket() {
long endTime = startTime + 120000L;
if(!(System.currentTimeMillis() < endTime)) {
shutdown = true;
}
}
private void sleepFewSeconds() {
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException interruptedException) {
shutdown = true;
}
}
}
我要在这里批评整个class。您的特定问题的答案将会出现。
public class SocketClient{
private volatile boolean isConnected;
你不需要这个。 socket == null
也行。
private int port;
private int retryCount;
private long startTime;
private String hostName;
private DataInputStream input;
private DataOutputStream output;
private Socket socket;
public SocketClient(int port, String hostname) throws IOException {
this.port = port;
this.hostName = hostname;
establishConnection();
}
public void shutdown() {
try {
shutdown = true;
input.close();
output.close();
socket.close();
您不需要所有这些关闭,而且您按错误的顺序执行它们。 output.close()
就足够了,无论如何它肯定是第一个。
} catch (Exception e) {
logger.debug("Exception in shutdown:" + e.getMessage());
}
}
public String getMessage() {
BufferedReader reader = null;
BufferedReader
应该是实例变量,不是局部变量。它被缓冲了。如果将其设为局部变量,您将丢失数据。
try {
StringBuilder builder = new StringBuilder();
reader = new BufferedReader(new
InputStreamReader(tcpSocket.getInputStream()));
do {
builder.append(reader.readLine());
} while((reader.ready()));
你不需要这一切。如果消息是单行,你只需要 return reader.readLine()
,你需要 caller 检查它是否为空,如果是,则关闭套接字,停止阅读, etc. 如果消息多于一行,这是对 ready()
的误用:它当然 而不是 消息结束的指示符。从您的问题下的评论看来,您甚至不应该拥有 方法 :只需将套接字输入流直接连接到您的 XML 解析器并让 它 阅读。
if (builder.length() == 0)
return "EmptyString";
不要这样做。 Return ""
或空。不要为您的应用程序编写必须解码的 new 魔法字符串。
return builder.toString();
} catch (IOException e) {
return "EmptyString";
同上。
} finally {
try {
if(reader != null)
reader.close();
你应该不关闭这里的reader。关闭它会关闭套接字,因此您永远不会收到其他消息。
} catch(IOException e) {
logger.error("unable to close reader");
}
}
}
private void establishConnection() {
retryCount = 1;
startTime = System.currentTimeMillis();
while (!shutdown) {
try {
if(!isConnected) {
socket = new Socket(hostName,port);
socket.setKeepAlive(true);
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
isConnected = true;
shutdown = true;
这里为什么要设置shutdown
为true
?什么都没有关闭。这是一个全新的插座。
}
} catch (Exception exception) {
isConnected = false;
sleepFewSeconds();
reconnectSocket();
}
练习不好。 Socket.connect()
,由 new Socket(...)
内部调用,已经重试,而且你应该区分连接失败异常,而不是对它们都采用相同的策略。例如,'connection timeout' 已经阻塞了一分钟左右:您不需要 另一个 睡眠; 'connection refused' 意味着没有任何监听,所以重试完全没有意义。
private void reconnectSocket() {
long endTime = startTime + 120000L;
if(!(System.currentTimeMillis() < endTime)) {
shutdown = true;
}
}
private void sleepFewSeconds() {
try {
TimeUnit.MILLISECONDS.sleep(20);
这不是 'few seconds'。 20毫秒,这在网络编程中至少有两个数量级是不够的,当然应该有任何睡眠。
} catch (InterruptedException interruptedException) {
shutdown = true;
shutdown
似乎永远不会为假。我怀疑你是否想过它的真正含义,我怀疑你是否真的需要它。
至于你的调用代码:
public void run() {
while (!shutdown) {
try {
if(socketClient != null) {
如果 socketClient
为空,此循环将无意义地旋转。确定这个方法应该构造套接字客户端?
String message = socketClient.getMessage();
logger.info ("Message size:" + message.length ());
这里你没有检查 null 并且没有正确响应,这将是关闭套接字并退出循环。相反,你会在这里得到一个 NPE。
if(!message.equals("EmptyString")) {
process(message);
见上文。不要给自己发特殊的短信。如果有一天对等方需要发送那个会怎样?
}
}
} catch (Exception exception) {
logger.info("Unable to read the socket message" +exception);
无法接受。这个 catch 在循环内部,它基本上忽略了异常。结果是,此循环将再次无意义地旋转任何异常。您正在调用的方法应该声明为 throw IOException
,这就是您应该在此处捕获的全部内容。目前你甚至会在 NullPointerException
上旋转。
在client socket中,我写了一个线程来不断读取socket的inputStream。这里我使用了一个while循环来无限读取。但是需要更多CPU;因此是否有可能减少 CPU。请添加您的建议。 也可以为 inputStream 添加侦听器。
线程代码:
public void run() {
while (!shutdown) {
try {
if(socketClient != null) {
String message = socketClient.getMessage();
logger.info ("Message size:" + message.length ());
if(!message.equals("EmptyString")) {
process(message);
}
}
} catch (Exception exception) {
logger.info("Unable to read the socket message" +exception);
}
}
}
SocketClient.java
public class SocketClient{
private volatile boolean isConnected;
private int port;
private int retryCount;
private long startTime;
private String hostName;
private DataInputStream input;
private DataOutputStream output;
private Socket socket;
public SocketClient(int port, String hostname) throws IOException {
this.port = port;
this.hostName = hostname;
establishConnection();
}
public void shutdown() {
try {
shutdown = true;
input.close();
output.close();
socket.close();
} catch (Exception e) {
logger.debug("Exception in shutdown:" + e.getMessage());
}
}
public String getMessage() {
BufferedReader reader = null;
try {
StringBuilder builder = new StringBuilder();
reader = new BufferedReader(new
InputStreamReader(tcpSocket.getInputStream()));
do {
builder.append(reader.readLine());
} while((reader.ready()));
if (builder.length() == 0)
return "EmptyString";
return builder.toString();
} catch (IOException e) {
return "EmptyString";
} finally {
try {
if(reader != null)
reader.close();
} catch(IOException e) {
logger.error("unable to close reader");
}
}
}
private void establishConnection() {
retryCount = 1;
startTime = System.currentTimeMillis();
while (!shutdown) {
try {
if(!isConnected) {
socket = new Socket(hostName,port);
socket.setKeepAlive(true);
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
isConnected = true;
shutdown = true;
}
} catch (Exception exception) {
isConnected = false;
sleepFewSeconds();
reconnectSocket();
}
}
}
private void reconnectSocket() {
long endTime = startTime + 120000L;
if(!(System.currentTimeMillis() < endTime)) {
shutdown = true;
}
}
private void sleepFewSeconds() {
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException interruptedException) {
shutdown = true;
}
}
}
我要在这里批评整个class。您的特定问题的答案将会出现。
public class SocketClient{
private volatile boolean isConnected;
你不需要这个。 socket == null
也行。
private int port;
private int retryCount;
private long startTime;
private String hostName;
private DataInputStream input;
private DataOutputStream output;
private Socket socket;
public SocketClient(int port, String hostname) throws IOException {
this.port = port;
this.hostName = hostname;
establishConnection();
}
public void shutdown() {
try {
shutdown = true;
input.close();
output.close();
socket.close();
您不需要所有这些关闭,而且您按错误的顺序执行它们。 output.close()
就足够了,无论如何它肯定是第一个。
} catch (Exception e) {
logger.debug("Exception in shutdown:" + e.getMessage());
}
}
public String getMessage() {
BufferedReader reader = null;
BufferedReader
应该是实例变量,不是局部变量。它被缓冲了。如果将其设为局部变量,您将丢失数据。
try {
StringBuilder builder = new StringBuilder();
reader = new BufferedReader(new
InputStreamReader(tcpSocket.getInputStream()));
do {
builder.append(reader.readLine());
} while((reader.ready()));
你不需要这一切。如果消息是单行,你只需要 return reader.readLine()
,你需要 caller 检查它是否为空,如果是,则关闭套接字,停止阅读, etc. 如果消息多于一行,这是对 ready()
的误用:它当然 而不是 消息结束的指示符。从您的问题下的评论看来,您甚至不应该拥有 方法 :只需将套接字输入流直接连接到您的 XML 解析器并让 它 阅读。
if (builder.length() == 0)
return "EmptyString";
不要这样做。 Return ""
或空。不要为您的应用程序编写必须解码的 new 魔法字符串。
return builder.toString();
} catch (IOException e) {
return "EmptyString";
同上。
} finally {
try {
if(reader != null)
reader.close();
你应该不关闭这里的reader。关闭它会关闭套接字,因此您永远不会收到其他消息。
} catch(IOException e) {
logger.error("unable to close reader");
}
}
}
private void establishConnection() {
retryCount = 1;
startTime = System.currentTimeMillis();
while (!shutdown) {
try {
if(!isConnected) {
socket = new Socket(hostName,port);
socket.setKeepAlive(true);
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
isConnected = true;
shutdown = true;
这里为什么要设置shutdown
为true
?什么都没有关闭。这是一个全新的插座。
}
} catch (Exception exception) {
isConnected = false;
sleepFewSeconds();
reconnectSocket();
}
练习不好。 Socket.connect()
,由 new Socket(...)
内部调用,已经重试,而且你应该区分连接失败异常,而不是对它们都采用相同的策略。例如,'connection timeout' 已经阻塞了一分钟左右:您不需要 另一个 睡眠; 'connection refused' 意味着没有任何监听,所以重试完全没有意义。
private void reconnectSocket() {
long endTime = startTime + 120000L;
if(!(System.currentTimeMillis() < endTime)) {
shutdown = true;
}
}
private void sleepFewSeconds() {
try {
TimeUnit.MILLISECONDS.sleep(20);
这不是 'few seconds'。 20毫秒,这在网络编程中至少有两个数量级是不够的,当然应该有任何睡眠。
} catch (InterruptedException interruptedException) {
shutdown = true;
shutdown
似乎永远不会为假。我怀疑你是否想过它的真正含义,我怀疑你是否真的需要它。
至于你的调用代码:
public void run() {
while (!shutdown) {
try {
if(socketClient != null) {
如果 socketClient
为空,此循环将无意义地旋转。确定这个方法应该构造套接字客户端?
String message = socketClient.getMessage();
logger.info ("Message size:" + message.length ());
这里你没有检查 null 并且没有正确响应,这将是关闭套接字并退出循环。相反,你会在这里得到一个 NPE。
if(!message.equals("EmptyString")) {
process(message);
见上文。不要给自己发特殊的短信。如果有一天对等方需要发送那个会怎样?
}
}
} catch (Exception exception) {
logger.info("Unable to read the socket message" +exception);
无法接受。这个 catch 在循环内部,它基本上忽略了异常。结果是,此循环将再次无意义地旋转任何异常。您正在调用的方法应该声明为 throw IOException
,这就是您应该在此处捕获的全部内容。目前你甚至会在 NullPointerException
上旋转。