首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Socket 伺服器進階實戰:從單執行緒到連線池支援上千併發

     編輯:Java 相關知識

基礎回顧:Socket 通訊五步驟

  1. Client:new Socket(ip, port)
  2. 雙向:getInputStream()/getOutputStream()
  3. 包裝:BufferedReader/PrintWriter 便利文本處理
  4. 讀寫資料
  5. 關閉流與 Socket (順序:先關 Writer 再關 Reader,否則通道中斷導致資料發不出去)

階段一:單執行緒阻塞式伺服器

ServerSocket server = new ServerSocket(port);
while (true) {
  Socket client = server.accept();      // 阻塞等待
  handleConnection(client);             // 完整處理才能接受下一個
}

缺點:一次只能服務一個客戶端,handleConnection 耗時 (如大檔傳輸) 會導致後續連線排隊甚至超時。

階段二:多執行緒伺服器 (Thread-per-Connection)

while (true) {
  Socket client = server.accept();
  new Thread(new ConnectionHandler(client)).start(); // 每連線一線程
}
  • ConnectionHandler implements Runnable,將原 handleConnection 邏輯移入 run()。
  • ServerSocket 建構式:new ServerSocket(port, backlog),backlog 指定作業系統接收隊列長度 (預設 50)。超過隊列的新連線會被拒絕 (Connection refused)。
  • 優點:並發處理能力大幅提升。
  • 缺點:線程建立/銷毀開銷大,併發數千時記憶體耗盡、上下文切換頻繁導致效能崩潰。

階段三:連線池伺服器 (固定線程池 + 隊列)

核心思想:啟動固定數量的 Handler 線程 (如 3 個),共享一個 任務隊列 (LinkedList)。主線程 accept() 後將 Socket 放入隊列並 notifyAll();Handler 線程 wait() 取任務處理。

關鍵代碼結構

// 伺服器主類
class PooledRemoteFileServer {
  void setUpHandlers() {
    for (int i=0; i pool = new LinkedList<>();
  Socket connection;

  static void processRequest(Socket s) {
    synchronized (pool) {
      pool.add(s);
      pool.notifyAll(); // 喚醒等待的 Handler
    }
  }

  public void run() {
    while (true) {
      synchronized (pool) {
        while (pool.isEmpty())
          pool.wait(); // 隊列空則等待
        connection = pool.remove(0); // 取任務
      }
      handleConnection(); // 處理實際業務
    }
  }
}

同步細節解析

  • synchronized(pool) 保護共享隊列的複合操作 (檢查+取出/加入+通知) 原子性。
  • pool.wait() 會釋放鎖,讓 processRequest 能獲得鎖加入任務;被喚醒後重新獲取鎖繼續執行。
  • notifyAll() 喚醒所有等待線程,但只有一個能搶到任務 (隊列移除),其餘重新進入 wait()。這稱為「驚群效應」,高併發下可改用 notify() 或 ReentrantLock + Condition 優化。
  • 固定線程數 = 最大並發處理能力,天然限流保護伺服器資源。
  • 線程只在啟動時建立一次,消除反覆建立/銷毀開銷。

優缺點總結

模型併發能力資源控制實作複雜度適用場景
單執行緒極低無最低教學、極低負載
Thread-per-Connection中 (受限於線程數)無 (線程無上限)低中低負載、短連線
連線池 (固定線程+隊列)高 (可配置)精確控制線程/隊列上限中生產環境、長連線、高併發

生產級建議:直接使用成熟框架

手寫連線池教學意義大於實戰。實務請採用:

  • Netty:事件驅動非阻塞 I/O (NIO),單線程處理萬級併發,業界標準。
  • Apache MINA:類似 Netty 的 NIO 框架。
  • Java NIO.2 (AsynchronousSocketChannel):JDK 7+ 原生非阻塞 API。
  • ExecutorService + ThreadPoolExecutor:替代手工線程池,配合 BlockingQueue 即可實現生產級連線池。

封裝建議:Facade 模式隱藏底層細節

定義 ClientSocketFacade/ServerSocketFacade 介面,上層業務邏輯僅依賴 Facade,底層可隨時替換為阻塞 IO、NIO、Netty 等實現,符合依賴倒置原則。

結語

從 ServerSocket.accept() 到固定線程池+共享隊列,我們一步步解決了「一次只能服務一個」、「線程無限增長」、「頻繁建立銷毀」三大痛點。理解這條演進路徑,才能真正駕馭 Netty 等高階框架的設計哲學。Java 網路編程,核心永遠是「用優秀的 OO 設計封裝底層位元組細節,讓業務邏輯純粹、可測試、可替換」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved