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

Java 用于读取套接字流的线程占用更多CPU使用率,java,multithreading,sockets,tcp,cpu-usage,Java,Multithreading,Sockets,Tcp,Cpu Usage,在客户端套接字中,我编写了一个线程来连续读取套接字的输入流。这里我使用了while循环来无限读取。然而,它需要更多的CPU;因此,有可能减少CPU。请添加您的建议。 也可以为inputStream添加侦听器 线程代码: public void run() { while (!shutdown) { try { if(socketClient != null) { String message = socketClient.getMessage();

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

}
公共类SocketClient{
私有布尔不连通;
专用int端口;
私人内部检索计数;
私人长启动时间;
私有字符串主机名;
私有数据输入流输入;
私有数据输出流输出;
专用插座;
公共SocketClient(int端口,字符串主机名)引发IOException{
this.port=端口;
this.hostName=主机名;
建立连接();
}
公共空间关闭(){
试一试{
关机=真;
input.close();
output.close();
socket.close();
}捕获(例外e){
debug(“关闭时异常:+e.getMessage());
}
}
公共字符串getMessage(){
BufferedReader reader=null;
试一试{
StringBuilder=新的StringBuilder();
读卡器=新的BufferedReader(新的
InputStreamReader(tcpSocket.getInputStream());
做{
builder.append(reader.readLine());
}while((reader.ready());
如果(builder.length()==0)
返回“清空字符串”;
返回builder.toString();
}捕获(IOE异常){
返回“清空字符串”;
}最后{
试一试{
if(读卡器!=null)
reader.close();
}捕获(IOE异常){
logger.错误(“无法关闭读卡器”);
}
}
}
私有连接(){
retryCount=1;
startTime=System.currentTimeMillis();
而(!关机){
试一试{
如果(!未连接){
套接字=新套接字(主机名、端口);
socket.setKeepAlive(true);
输入=新的DataInputStream(socket.getInputStream());
output=新的DataOutputStream(socket.getOutputStream());
断开连接=正确;
关机=真;
} 
}捕获(异常){
断开连接=错误;
sleepFewSeconds();
重新连接套接字();
}
}
}
私有void重新连接套接字(){
长结束时间=开始时间+120000L;
if(!(System.currentTimeMillis()
我将在这里对全班同学进行点评。您特定问题的答案将出现

public class SocketClient{
private volatile boolean isConnected;
你不需要这个<代码>套接字==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()));
你不需要这些。如果消息是单行,则只需
返回reader.readLine()
,您需要调用者检查它是否为空,如果为空,请关闭套接字,停止读取,等等。如果消息不止一行,则这是误用
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;
为什么要在此处将
关机设置为
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);
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);

不能接受。此捕获位于循环内部,它实际上忽略了异常。结果是,这个循环在任何异常上都会毫无意义地旋转。您正在调用的方法应该声明为抛出
IOException
,这就是您在这里应该捕获的全部内容。目前,您甚至可以在
NullPointerException
上旋转

我看到您面临着很多问题,因为您的系统的磁盘使用率很高,多次导致滞后。我找到了解决您问题的方法
            }
        } 
    } catch (Exception exception) {
        logger.info("Unable to read the socket message" +exception);