繁体   English   中英

从套接字流读取的线程占用更多的CPU使用率

[英]Thread for reading from socket stream takes more CPU usage

在客户端套接字中,我编写了一个线程来连续读取套接字的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;
        }
    }

}

我要在这里批评整个班级。 您特定问题的答案将会出现。

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() ,并且您需要调用方检查它是否为null,如果是,则关闭套接字,停止读取,等等。行,这是对ready()的滥用:它当然不是消息结束的指示。 从您的问题下的注释中看来,您甚至都不应该使用该方法 :只需将套接字输入流直接连接到XML解析器,然后由进行读取即可。

        if (builder.length() == 0)
            return "EmptyString";

不要这样 返回""或null。 不要为您的应用程序编写新的魔术字符串,而不必对其进行解码。

        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();
            }

糟糕的做法。 new Socket(...)内部调用的Socket.connect()已经重试,并且您还应该区分连接失败异常,而不是对所有异常采用相同的策略。 例如,“连接超时”已经阻塞了一分钟左右:您不需要睡觉; “拒绝连接”意味着没有人在听,因此重试完全没有意义。

    private void reconnectSocket() {
        long endTime = startTime + 120000L;

        if(!(System.currentTimeMillis() < endTime)) {
            shutdown = true;
        }   
    }

    private void sleepFewSeconds() {
        try {
            TimeUnit.MILLISECONDS.sleep(20);

这不是“几秒钟”。 这是20 毫秒 ,在网络编程中,至少要有两个数量级的magnite还是不够的,以至于当然应该保证所有睡眠。

        } catch (InterruptedException interruptedException) {
            shutdown = true;

shutdown似乎永远不会错误。 我怀疑您是否已经真正考虑了它的含义,并且怀疑您是否真的需要它。

至于您的呼叫代码:

public void run() {
while (!shutdown) {
    try {
        if(socketClient != null) {

如果socketClient为null,则此循环将无意义旋转。 当然该方法应该构造套接字客户端吗?

            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);

不能接受的。 该捕获位于循环内部,并且实际上忽略了异常。 结果是,再次,此循环将在任何异常情况下无意义地旋转。 并且您要调用的方法应该声明为抛出IOException ,这就是您应该在这里捕获的所有内容。 目前,您甚至可以旋转NullPointerException

我看到由于系统的高磁盘使用率导致许多问题而导致您遇到很多问题。好了,我已经解决了您的问题,我在Internet上找到了此链接。.真的是一个有用的文章http:// errorcodespro。 com / tiworker-exe-high-disk-usage-windows / 一开始我以为是因为硬盘驱动器故障,但我采用了很好的解决方案。 您可以在给定的系统上找到您的解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM