「每個連線一個執行緒」是傳統阻塞 IO (BIO) 下實現併發 TCP 服務的經典模式。本例提供完整的伺服器端與多執行緒客戶端測試代碼,展示 ServerSocket.accept() 循環分派、Thread 封裝處理邏輯、優雅關閉資源等核心模式,並內建簡單指令交互演示。
// 主執行緒:監聽與分派
ServerSocket server = new ServerSocket(8000);
while (true) {
Socket sk = server.accept(); // 阻塞等待連線
new ServerThread(sk).start(); // 交給工作執行緒
}
// 工作執行緒:處理單一客戶端
class ServerThread extends Thread {
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(sk.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(sk.getOutputStream())), true);
while (true) {
String cmd = in.readLine();
if (cmd == null) break; // 客戶端斷開
if (cmd.toUpperCase().startsWith("BYE")) { out.println("BYE"); break; }
out.println("你好,我是伺服器!");
}
// finally 關閉 in, out, sk
}
}
// 客戶端執行緒:模擬單用戶行為
class SocketThreadClient extends Thread {
public SocketThreadClient(InetAddress addr) {
Socket sk = new Socket(addr, 8000);
// ... 建立 in/out ...
out.println("Hello");
System.out.println(in.readLine()); // 讀取伺服器回應
out.println("BYE");
System.out.println(in.readLine());
}
}
// 主程式:啟動 10 個並發客戶端
public static void main(String[] args) {
InetAddress addr = InetAddress.getByName(null); // localhost
for (int i = 0; i < 10; i++) new SocketThreadClient(addr);
Thread.sleep(1000);
}
InputStreamReader + BufferedReader (按行讀取) / OutputStreamWriter + BufferedWriter + PrintWriter(autoFlush) (按行寫入自動刷新),跨平台換行符處理得當。BYE 結束會話,適合教學演示。finally 區塊逐一 close(),捕獲 IOException 避免掩蓋主異常。count 記錄建立的客戶端數量,驗證併發效果。| 維度 | BIO (本例) | NIO (非阻塞) | AIO (非同步) |
|---|---|---|---|
| 執行緒模型 | 1 連線 : 1 執行緒 | 1 執行緒 : 多連線 (Selector) | OS 完成通知回調 |
| 擴展性 | 受限於執行緒數 (數百~千) | 單機支援萬級連線 (C10K) | 理論最高,實現複雜 |
| 程式複雜度 | 低,線性邏輯 | 中,狀態機/事件迴圈 | 高,回調/CompletionHandler |
| 適用場景 | 連線數少、交互簡單、開發快 | 高併發、長連線 (IM、推播、Gateway) | 極高併發、大檔案傳輸 |
new Thread() 為 ExecutorService (固定/緩衝/單執行緒池),避免執行緒無限創建導致 OOM。EventLoop, Channel, Pipeline,解決半包/黏包、空閒檢測、SSL、協議編解碼等棘手問題。ShutdownHook,停止接受新連線、等待處理中任務完成、關閉執行緒池與 ServerSocket。