Java socket编程 CPU占用率高的问题解决

本人用Java socket编程,多线程程序,发现CPU占用率非常高,经过一番研究,问题解决,特记录如下。

首先上问题代码(代码同时实现了超时机制):

    /**
     * 发送完毕以后等待服务器返回数据的函数 实现了超时机制
     */
    public Boolean awaitReturnOLD(int timeout) {
        Boolean result = false;

        // 上锁:实现超时机制第一步
        expectedArriveLatch = new CountDownLatch(1);

        //任务放到线程:实现超时机制第二步
        new Thread(new Runnable() {
            @Override
            public void run() {
                pullBuffer = null;
                int count = 0;
                while (true) {
                    try {
                        // 读信息
                        while (count == 0)
                            count = in.available();
                        byte[] b = new byte[count];
                        in.read(b);
                        LogUtils.debug(LABEL, "Thread get:" + new String(b));
    
                        // 叠加到接收缓冲区
                        pullBuffer = ArrayUtils.addAll(pullBuffer, b);

                        //判断是否已经收到想要的结果(约定结果以两个##包裹) 自己写的函数简单判断字符#的数量
                        if (PublicUtils.getByteCount(pullBuffer) >= 2)
                            break;
                    } catch (IOException e) {
                        LogUtils.debug(LABEL, "AwaitReturn failed.");
                    }
                }
                // 收到了想要的数据,解锁
                expectedArriveLatch.countDown();
            }
        }).start();
    
        // 等待解锁:实现超时机制第三步
        try {
            result = expectedArriveLatch.await(timeout, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            LogUtils.error(LABEL, e);
        }

        //正常收到则result = true 超时结束则result = fasle
        return result;
    }

以上代码单线程运行的时候,工作正常,多线程运行的时候,发现CPU占用率居高不下 。

参照以下文章内容,使用jstack和Process Explorer对程序进行了分析:

https://blog.csdn.net/hexin373/article/details/8846919?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

问题定位在如下一行代码:

                    try {
                        // 读信息
                        while (count == 0)
                            count = in.available();
                        byte[] b = new byte[count];
                        in.read(b);

深入了解,看一下官方API解释:public int available() throws IOException 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。这个方法的调用是立即返回的,于是乎在返回数据还没有到来的情况下,这个代码片段像极了死循环,所以才导致CPU巨高不下。

找到问题,就好解决了,改进代码片段如下:

                    while ((len = in.read(buf)) != -1) {
                        byte[] tmp = ArrayUtils.subarray(buf, 0, len);
                        pullBuffer = ArrayUtils.addAll(pullBuffer, tmp);

in.read(buf)方法是阻塞式的,会一直等到至少有一个字节数据的到来,阻塞方式不需要CPU轮询,不会占据CPU大量的时间片。

至此问题完美解决,特此记录。

(有人说循环间用sleep休眠就可以解决,但是本人不太喜欢用sleep,随便用sleep的都是耍流氓)

你可能感兴趣的:(JAVA编程)