You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何提升Java可创建线程数?TCP服务器高并发连接问题排查

问题背景

我开发了一款TCP服务器,用于对接传感器等嵌入式设备(需保持长连接实现实时控制),采用TCP Socket+私有二进制协议。当前用Executors.newCachedThreadPool()为每个连接分配独立线程处理,当并发连接达到9462个时,JVM无法创建新线程,报错如下:

[1805.442s][warning][os,thread] Failed to start thread "Unknown thread" - pthread_create failed (EAGAIN) for attributes: stacksize: 1024k, guardsize: 0k, detached.
[1805.442s][warning][os,thread] Failed to start the native thread for java.lang.Thread "Thread-15915"
Exception in thread "Thread-0" java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached
at java.base/java.lang.Thread.start0(Native Method)
at java.base/java.lang.Thread.start(Thread.java:802)
at socketservertest.TCPServer.run(TCPServer.java:139)
at java.base/java.lang.Thread.run(Thread.java:833)

此时系统仍有40%可用内存,目标是支持至少5万并发连接,需要调整系统和JVM配置,同时优化架构。


解决方案

一、Debian系统资源限制调整

系统层面的线程数、栈内存限制是当前直接瓶颈:

  1. 调整用户进程资源限制

    • 编辑/etc/security/limits.conf,添加或修改:
      your_username soft nproc 65535
      your_username hard nproc 65535
      your_username soft stack 262144
      your_username hard stack 262144
      
      其中nproc限制单个用户的最大进程/线程数,stack设置线程栈的软限制(单位:字节,262144即256k)。
    • 若用systemd管理服务,编辑/etc/systemd/system.conf,修改:
      DefaultLimitNPROC=65535
      DefaultLimitSTACK=262144
      
      执行systemctl daemon-reload生效。
  2. 调整内核参数

    • 临时生效:
      echo 100000 > /proc/sys/kernel/threads-max
      echo 200000 > /proc/sys/vm/max_map_count
      
    • 永久生效:编辑/etc/sysctl.conf,添加:
      kernel.threads_max = 100000
      vm.max_map_count = 200000
      
      执行sysctl -p生效。

二、JVM参数优化

默认JVM线程栈大小为1M,大量线程会占用大量堆外内存,需调整:

  • 减小线程栈大小:启动参数添加-Xss256k(根据实际业务调整,最低可到128k,需测试避免栈溢出)
  • 合理分配堆内存:不要把堆内存占满,留足够空间给线程栈。例如系统总内存32G的话,堆内存设为-Xmx16G,剩余内存可支撑5万线程(每个256k的话,50000*256k=12.5G,足够)。

三、架构优化(核心解决方案)

每个连接一个线程的模型根本无法支撑5万并发,即使调通系统参数,也会出现CPU上下文切换过载、内存耗尽的问题,必须改用IO多路复用模型:

  1. 替换线程池类型
    立即停止使用Executors.newCachedThreadPool(),它会无限制创建线程。改用固定大小线程池,比如根据CPU核心数设置:

    this._threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
    

    但这只是临时过渡,无法解决5万连接的根本问题。

  2. 切换到Java NIO/Selector模型
    使用Java NIO的Selector实现多路复用,单个线程可以处理成百上千个连接的IO事件,避免为每个连接分配线程。核心思路是:

    • 用ServerSocketChannel监听连接,注册到Selector
    • 每个客户端的SocketChannel注册到Selector,监听读/写事件
    • 用少量线程轮询Selector,处理就绪的IO事件
  3. 使用Netty框架(推荐)
    Netty封装了NIO细节,提供了成熟的TCP长连接解决方案,支持百万级并发,适合嵌入式设备的长连接场景。它通过Reactor模型实现多路复用,无需手动管理线程和IO事件,能大幅降低开发复杂度。


内容的提问来源于stack exchange,提问作者Dominick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 07:53:16