Socket編程與線程

來源:互聯網
上載者:User

在開發Socket項目的時候,如果是開發一個自己玩玩,當然不用考慮效率、安全性等問題,可是如果是一個企業級的,你就不得不關注這幾點。本系列文章將我們實驗室裡的Socket程式變成企業級的應用。
        NIO編程肯定是一個很好的解決方案,不過這部分留在以後討論。今天我想說說如何讓你的阻塞的Scoket程式高效、安全的跑起來。
        一開始,大家會編出一個單線程的Scoket程式,然後我們發現這個程式根本不能夠串連多個用戶端,於是我們引入“多線程”,使我們的程式能夠同時處理多個用戶端。
        我相信,到現在為止如果沒有深入研究過Socket編程,大家一般還是停留在“一客戶一線程”的初級模式。如果是個位元的客戶,當然你不會發現什麼明顯的效能問題。但是如果你的客戶串連數量達到百位級,我靠,你的CPU就關顧著在各個線程間切換,你的記憶體似乎也有些吃不消了(每個線程都有自己獨立的記憶體),更多的系統資源的消耗,更多的線程上下文轉換,更複雜的線程管理(OS有一套自己的機制),將拖垮你的application。再加上多用戶端嘗試並發串連,及時響應用戶端的串連將變得像癩蛤蟆追求天鵝一樣不給力,因為線程的建立將佔用伺服器大量的CPU周期。
        從單線程到多線程我們沒法解決的問題,必然有新的英雄站出來解決,他就是“線程池”。
Java代碼

  • import java.io.IOException;  
  • import java.net.ServerSocket;  
  • import java.net.Socket;  
  • import java.util.logging.Level;  
  • import java.util.logging.Logger;  
  • /**
  • * ThreadPool示範
  • * @project : socket
  • * @author  賈懂凱 @ netjava  
  • * @date  2010-12-14 下午12:24:40
  • * @since jdk1.6.0_10
  • */
  • public
    class TCPServerPool {  
  •     public
    static
    void main(String args[]) throws IOException{  
  •         //ensure the parameter is right!
  •         if(args.length!=2){  
  •             throw
    new IllegalArgumentException("Parameter(s):<port> <ThreadSize>");  
  •         }  
  •         int server_port=Integer.parseInt(args[0]);  
  •         int threadpool_size=Integer.parseInt(args[1]);  
  •         //create a server socket to accept client connection requests
  •         final ServerSocket serSock=new ServerSocket(server_port);  
  •         final Logger logger=Logger.getLogger("thredPoolLog");  
  •         //spawn a fixed number of threds to service clients
  •         for(int i=0;i<threadpool_size;i++){  
  •             Runnable run=new Runnable(){  
  •                 public
    void run() {  
  •                     while(true){  
  •                         try {  
  •                             Socket clientSock=serSock.accept();  
  •                             /**
  •                              * 把它交給一個獨立的handler處理
  •                              * 你可以將handler定義為一個獨立的線程(注意效能)
  •                              * 或者定義為一個靜態方法(注意並發的同步問題)。
  •                              */
  •                         } catch (IOException e) {  
  •                             logger.log(Level.WARNING,"Client accept failed",e);  
  •                         }  
  •                     }  
  •                 }  
  •             };  
  •             Thread t=new Thread(run,"Thread-"+i);  
  •             t.start();  
  •             logger.info("create and start a thread named "+t.getName());  
  •         }  
  •     }  
  • }  

import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.util.logging.Level;import java.util.logging.Logger;/** * ThreadPool示範 * @project : socket * @author  賈懂凱 @ netjava  * @date  2010-12-14 下午12:24:40 * @since jdk1.6.0_10 */public class TCPServerPool {                public static void main(String args[]) throws IOException{                //ensure the parameter is right!                if(args.length!=2){                        throw new IllegalArgumentException("Parameter(s):<port> <ThreadSize>");                }                int server_port=Integer.parseInt(args[0]);                int threadpool_size=Integer.parseInt(args[1]);                                //create a server socket to accept client connection requests                final ServerSocket serSock=new ServerSocket(server_port);                final Logger logger=Logger.getLogger("thredPoolLog");                                //spawn a fixed number of threds to service clients                for(int i=0;i<threadpool_size;i++){                        Runnable run=new Runnable(){                                public void run() {                                        while(true){                                                try {                                                        Socket clientSock=serSock.accept();                                                        /**                                                         * 把它交給一個獨立的handler處理                                                         * 你可以將handler定義為一個獨立的線程(注意效能)                                                         * 或者定義為一個靜態方法(注意並發的同步問題)。                                                         */                                                } catch (IOException e) {                                                        logger.log(Level.WARNING,"Client accept failed",e);                                                }                                        }                                }                        };                        Thread t=new Thread(run,"Thread-"+i);                        t.start();                        logger.info("create and start a thread named "+t.getName());                }        }        }
     這裡我為accept()方法加上了線程池,我們發現,我們不必擔心少量的多個客戶並發串連的問題了,因為有多個線程對應的accept()在等待用戶端串連進來。一旦客戶成功串連進來,該線程重新返回線程池。如果並發訪問的用戶端超過線程池的size,那麼串連請求將在網路中形成一個隊列等待,這明顯是不利於維護的,並且線程的大小沒有適應性,因為它總是一成不變的。
    並且串連進來的用戶端顯然不能交給單獨的線程來處理,否則我們控制線程數量過多造成的效能瓶頸的初衷將無疾而終。不過,如果給串連進來的用戶端建立一個線程池,就要考慮到維護問題,我們建立一個等待隊列,來維護那些超過用戶端線程池size的線程。這樣將引起一致命的問題,如果其中有幾個正在接受服務的線程阻塞等待或者由於未捕獲異常死亡,在等待隊列中的線程將因遲遲得不到資源而被餓死。
     線程池的初步使用出現了這麼多問題,問題總是伴隨著被解決的可能性誕生的,就像出現了怪獸總會出現奧特曼一樣,於是我們的英雄又出現了-“Executor”,它是系統提供的,它可以協助我們來管理線程池。

 

本文轉自www.35java.com 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.