Поток для чтения из потока сокетов требует больше ресурсов процессора

В клиентском сокете я написал поток для непрерывного чтения 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/. В начале я думал, что это из-за сбоя жесткого диска, но я применил решение, которое работало очень хорошо. Вы можете найти свое решение в данной системе.

Другие вопросы по тегам