客戶端 TCP 連線後發送資料,伺服器收到立即原樣回傳,連線持續至客戶端關閉。核心挑戰:同時處理多客戶端連線。
public class EchoServer implements Runnable {
public void run() {
try (ServerSocket svr = new ServerSocket(7)) {
while (true) {
Socket sock = svr.accept();
new Thread(new EchoSession(sock)).start(); // 每連線建立新執行緒
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
class EchoSession implements Runnable {
private final Socket socket;
EchoSession(Socket s) { this.socket = s; }
public void run() {
try (InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream()) {
byte[] buf = new byte[128];
int count;
while ((count = in.read(buf)) != -1) {
out.write(buf, 0, count); // 回顯
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
優點:邏輯簡單、阻塞式 API 直觀。
缺點:頻繁建立/銷毀執行緒開銷大、執行緒數無上限導致 OOM、上下文切換成本高。
public class PooledEchoServer implements Runnable {
public void run() {
try (ServerSocket svr = new ServerSocket(7)) {
// 固定大小線程池,這裡用簡易 SyncQueue + Worker 示意
SyncQueue queue = new SyncQueue<>(100);
for (int i = 0; i < 50; i++) new Thread(new Worker(queue)).start();
while (true) {
Socket sock = svr.accept();
queue.put(new EchoSession(sock)); // 任務入隊,工作者執行緒取出執行
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
改進:執行緒復用、控制併發上限、EchoSession 實作 Runnable 而非繼承 Thread,解耦任務與執行策略。
局限:固定池大小仍受限於執行緒數,C10K 問題未根治。
NIO 核心:非阻塞 I/O + 多路複用 (Selector) + 事件驅動。少量執行緒(通常 1~CPU 核心數)即可處理成萬併發連線。
// 核心邏輯同前文 NioEchoServer,關鍵點:
// 1. ServerSocketChannel.configureBlocking(false)
// 2. Selector.open() + serverChannel.register(selector, OP_ACCEPT)
// 3. while(select() > 0) { 遍歷 selectedKeys 處理 ACCEPT/READ/WRITE }
// 4. 處理 READ 時解碼完整訊息,編碼回應,必要時註冊 OP_WRITE
// 5. 連線關閉時 channel.close(),取消註冊
OP_ACCEPT,建立連線後分派給 Sub Reactor。OP_READ/WRITE,充分利用多核 CPU。這正是 Netty 預設架構(NioEventLoopGroup boss + worker)。
| 併發規模 | 推薦架構 | 典型框架 |
|---|---|---|
| < 500 | Thread Pool + BIO | Tomcat (預設連接器)、Spring Boot 內嵌容器 |
| 500 ~ 5,000 | NIO Reactor (單/多執行緒) | Netty、Undertow、Jetty NIO 連接器 |
| > 10,000 | 主從 Reactor + 業務線程池 | Netty (預設)、gRPC Java、Apache Dubbo |
從「一連線一執行緒」到「線程池複用」再到「事件驅動非阻塞」,Java 網路伺服器架構演進本質是資源利用率與擴展性的持續優化。現代微服務、即時通訊、遊戲伺服器幾乎全面採用 Netty 等成熟 NIO 框架,開發者應聚焦業務邏輯,而非重複造輪子。