Поток для чтения из потока сокетов требует больше ресурсов процессора
В клиентском сокете я написал поток для непрерывного чтения inputStream сокета. Здесь я использовал цикл while, чтобы читать бесконечно. Однако это требует больше ресурсов процессора; следовательно возможно ли уменьшить процессор. Пожалуйста, добавьте ваши предложения. Также возможно добавить слушателей для 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;
}
}
}
2 ответа
Я собираюсь критиковать весь класс здесь. Ответ на ваш конкретный вопрос появится.
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()
и вам нужно, чтобы вызывающий проверил, было ли оно пустым, и если это так, закройте сокет, прекратите чтение и т. д. Если сообщение содержит более одной строки, это неправильное использование ready()
: это, конечно, не показатель конца сообщения. Из комментариев под вашим вопросом следует, что у вас даже не должно быть метода: просто подключите поток ввода сокетов непосредственно к вашему XML-анализатору и дайте ему прочитать.
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;
Почему вы настраиваете shutdown
в true
Вот? Ничего еще не отключено. Это совершенно новая розетка.
}
} catch (Exception exception) {
isConnected = false;
sleepFewSeconds();
reconnectSocket();
}
Плохая практика Socket.connect()
, который вызывается внутри new Socket(...)
, уже повторяется, а также вы должны различать исключения сбоя соединения, а не принимать одну и ту же стратегию для них всех. Например, "тайм-аут соединения" будет уже заблокирован на минуту или около того: вам не нужен другой сон; и "отказано в соединении" означает, что ничего не слушается, поэтому повторение попытки абсолютно бессмысленно.
private void reconnectSocket() {
long endTime = startTime + 120000L;
if(!(System.currentTimeMillis() < endTime)) {
shutdown = true;
}
}
private void sleepFewSeconds() {
try {
TimeUnit.MILLISECONDS.sleep(20);
Это не "несколько секунд". Это 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 ());
Здесь вы не можете проверить нулевое значение и не можете ответить соответствующим образом, то есть закрыть сокет и выйти из цикла. Вместо этого вы получите NPE здесь.
if(!message.equals("EmptyString")) {
process(message);
Смотри выше. Не отправляйте себе специальные текстовые сообщения. Что произойдет, если сверстник должен отправить это один день?
}
}
} catch (Exception exception) {
logger.info("Unable to read the socket message" +exception);
Неприемлемый. Этот улов находится внутри цикла и по сути игнорирует исключение. В результате этот цикл снова будет бессмысленно вращаться при любом исключении. И методы, которые вы вызываете, должны быть объявлены как IOException
и это все, что вы должны поймать здесь. В настоящее время вы будете вращаться даже на NullPointerException
,
Я вижу, что вы сталкиваетесь с большой проблемой из-за высокого использования диска вашей системы, что много раз приводит к отставанию. Ну, у меня есть решение вашей проблемы, я нашел эту ссылку в Интернете... действительно справочная статья http://errorcodespro.com/tiworker-exe-high-disk-usage-windows/. В начале я думал, что это из-за сбоя жесткого диска, но я применил решение, которое работало очень хорошо. Вы можете найти свое решение в данной системе.