为啥Java的socket.connect()会消耗100%的cpu资源?

Posted

技术标签:

【中文标题】为啥Java的socket.connect()会消耗100%的cpu资源?【英文标题】:Why does Java's socket.connect() consume 100% cpu resources?为什么Java的socket.connect()会消耗100%的cpu资源? 【发布时间】:2010-06-05 00:52:52 【问题描述】:

我创建了一个线程池,并为其分配了 50 个任务以连接到服务器。因此,一旦完成连接,发送一些数据,然后断开连接。它还将读取超时设置为 5 秒(当然长 5000 秒)。我什至将线程池的最大大小设置为 1。然后我在 linux 上启动它,并运行 htop(一个更好的 top 版本)来检查 CPU 使用率。我始终以 100% 的速度看到我的一个内核(2 核机器)。我用 hprof (-agentlib:hprof=cpu=samples,interval=20,depth=3) 对此进行了分析,并且 socket.connect() 达到了 99%。

这就是我觉得奇怪的地方,阻塞 IO 不是为了阻塞(因此等待)吗?我的 JDK 是(来自java -version):

OpenJDK Runtime Environment (IcedTea6 1.6.1) (6b16-1.6.1-3ubuntu3)

OpenJDK Server VM (build 14.0-b16, mixed mode)

Update1:同样的问题也出现在 Sun 的 JVM 上:

java -version
Java version "1.6.0_20"

Update2:这是由于本机的 doConnect 方法所致。有谁知道我如何查看这个本机/C 代码的源代码?

Update3:我登录到 windows 编写代码并测试它。它工作正常,没有 CPU 资源被占用。我重新登录到 linux,现在问题仍然存在,但还不如仅 1 次连接就以 100% 的速度将整个 CPU 内核软管...。这是代码:

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Vector;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


public class SocketTest 


    public static void main(String[] args) 
        new SocketTest();

    

    public SocketTest() 

        ThreadPoolExecutor tpe = (ThreadPoolExecutor) Executors.newFixedThreadPool(40);

        Vector<Callable<Object>> tasks = new Vector<Callable<Object>>();

        for (int i = 0; i < 1500; i++)
            tpe.submit(new Thread() 

                public void run() 
                    byte[] ip =  74, 125, 19, (byte)((Math.random()*253)+1);
                    Socket socket = new Socket();
                    try 
                        System.out.println("new thread: "+ip[3]);
                        socket.connect(new InetSocketAddress(InetAddress.getByAddress(ip), 80), 3000);
                        socket.close();
                     catch (UnknownHostException e) 
                        e.printStackTrace();
                     catch (IOException e) 
                        //no need to print
                    
                
            );

            try 
                tpe.invokeAll(tasks);
             catch (InterruptedException e1) 
                e1.printStackTrace();
            
            System.out.println("test");
            try 
                //too lazy to write actual code to wait for task completness...
                tpe.awaitTermination(9001, TimeUnit.DAYS);
             catch (InterruptedException e) 
                e.printStackTrace();
            
            System.out.println("test2");
    


【问题讨论】:

代码里肯定有东西,你能把相关的部分贴出来。您可能需要考虑到给您带来问题的最少代码量。 见更新2。它发生在 PlainSocketImpl 内部的 doConnect 方法中。这就是被灌输的东西。我没有任何方法会占用 CPU ..... 1500 个线程,你一定是在开玩笑吧?你怎么知道是连接?无论如何,做 1500 次会占用大量资源。如果您正在寻找 1500 个并发连接,那么您最好获得比您编写的更强大的东西。 @Romain Hippeau:“我什至将线程池设置为最大大小 1” 【参考方案1】:

我只是想评论一下,您似乎在滥用线程池,因为您实际上实例化了 Thread 类型的新对象 1500 次,只是为了将它们传递给实例化更多线程的线程池,以便运行您的任务。您通常应该做的是实例化一个 Runnable 并让线程池完成它的工作。我并不是说这是导致 CPU 阻塞的原因,但这确实是个问题。

【讨论】:

我觉得这里可以忽略线程池。我不应该在代码中提交带有该示例的示例,因为它不相关,我对此很懒惰。【参考方案2】:

抛开代码的设计问题(例如,tasks 从未真正使用过),我无法在 Windows 或 Ubuntu (12.04.2 LTS) 上重现高 CPU 使用率。

能否请将您的 JDK 升级到 1.7 (sudo apt-get install openjdk-7-jdk) 并告诉我您使用的是哪个版本的 JDK?我的是javac 1.7.0_25,例如(使用javac -version

在那之后我会尝试进一步挖掘......

【讨论】:

以上是关于为啥Java的socket.connect()会消耗100%的cpu资源?的主要内容,如果未能解决你的问题,请参考以下文章

java使用socket读取网页

java使用socket读取网页

Socket Connect问题

Java和.NET下socket转换错误记录

Flutter - Socket.Connect() - SocketException:操作系统错误:连接超时

socket connect 反复使用,为何到一定的时候connect不上服务器?