Java Socket场景下线程池未创建预期数量线程问题排查
问题分析与解决方案
我一眼就发现了问题的根源——你把线程池的创建逻辑放在了接受客户端连接的循环内部!
每次有新客户端发起连接时,你的代码都会执行ExecutorService executor = Executors.newFixedThreadPool(5),这意味着每个客户端都拥有一个独立的线程池。每个线程池只处理当前这一个客户端的请求,所以每个池里只会启动一个线程,线程名称自然就是pool-1-thread-1、pool-2-thread-1这种逐个递增池编号的格式。
要实现所有客户端共用同一个线程池的目标,你只需要把线程池的初始化代码移到循环外面,让它在服务器启动时只创建一次即可。
修改后的服务器代码
package testThreadPool; import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TCPServer2 { private static ServerSocket servSock; private static final int PORT = 1234; public static void main(String[] args) { System.out.println("Connecting to port......\n"); try { servSock = new ServerSocket(PORT); // step 1 } catch (IOException e) { System.out.println("Unable to connect to PORT 1234"); System.exit(1); } // 关键修改:把线程池创建移到循环外部,只初始化一次 ExecutorService executor = Executors.newFixedThreadPool(5); do { Socket link = null; try { link = servSock.accept(); } catch (IOException e) { e.printStackTrace(); } Runnable threadpool = new newClient2(link, "serverThread"); executor.execute(threadpool); } while(true); // 注意:如果需要优雅关闭服务器,记得在这里调用executor.shutdown() // executor.shutdown(); } } class newClient2 implements Runnable { private Scanner input; private PrintWriter output; private Socket link; private String name; public newClient2(Socket socket, String SerName) { link = socket; name = SerName; try { input = new Scanner(link.getInputStream()); output = new PrintWriter(link.getOutputStream(), true); } catch (IOException e) { e.printStackTrace(); } } public void run() { int numMessages = 0; String message = input.nextLine(); // step 4 try { while(!message.equals("***CLOSE***")) { numMessages++; output.println("Message " + numMessages + " : " + message); // step 4 System.out.println("name Thread: " + Thread.currentThread().getName()); message = input.nextLine(); // step 4 } } finally{ try { System.out.println("\n* Closing connection...."); link.close(); // step 5 } catch (IOException e) { System.out.println("Unable to disconnect!....."); System.exit(1); } } } }
额外说明
- 修改后,所有客户端连接都会提交到同一个固定大小为5的线程池,线程名称会按照
pool-1-thread-1、pool-1-thread-2...的格式递增,直到线程池的5个线程都被使用。 - 如果服务器需要优雅关闭,记得在退出循环后调用
executor.shutdown(),避免线程池资源泄漏。 - 你可以根据实际业务需求调整线程池的大小,比如使用
Executors.newCachedThreadPool()来动态调整线程数量,或者手动创建ThreadPoolExecutor来更精细地控制线程池参数。
内容的提问来源于stack exchange,提问作者phptraining
相关产品推荐
相关产品推荐

