OMG,到底在尋找什么..................
          (構(gòu)造一個完美的J2EE系統(tǒng)所需要的完整知識體系)
          posts - 198,  comments - 37,  trackbacks - 0
          原貼地址:http://www.gbunix.com/htmldata/2004_12/14/19/article_769_1.html

          我突然發(fā)現(xiàn)了利用接口實現(xiàn)多線程和利用類構(gòu)造線程體的不同了,以前我好像并沒有太多的注意.利用類構(gòu)造線程體的時候,需要使用這個類來定義線程對象,比如MyThread thread1=New MyThread(),而使用接口創(chuàng)建線程體的時候,只需要用到Thread類就可以了,比如Thread thread1=new Thread(MyThread).這在幾天前所講的多線程的Socket中均有體現(xiàn).

          前面不懈的努力使我現(xiàn)在可以繼續(xù)原先未完成的工作,正式向連接池版本的Socket進(jìn)發(fā)了.

          回顧一下我們是如何創(chuàng)建多線程的服務(wù)器MultiThreadRemoteFileServer的,這得看看前幾天的內(nèi)容了.概括起來,就是為每個等待連接的客戶new一個線程使用,來一個分配一個.每當(dāng)有客戶機(jī)申請一個連接時都在一個新 Thread 中創(chuàng)建一個新 ConnectionHandler(注:使用接口構(gòu)造的線程體).這意味著可能有一打 Thread在整個系統(tǒng)中運(yùn)行著.顯然,系統(tǒng)的開銷會因為連接客戶的數(shù)目的增長而不斷增加.我們不能夠不考慮到開銷增加到一定程度的時候系統(tǒng)會承受不住的可能.因此,得想個辦法限制連接客戶的數(shù)量,提高服務(wù)器的效率.

          那么解決的方案是:在服務(wù)器端,我們在服務(wù)器啟動時創(chuàng)建一定數(shù)量的PooledConnectionHandler,我們把進(jìn)入的連接放入一個連接池中并讓PooledConnectionHandler 打理剩下的事情.客戶端的程序完全不用修改,這樣設(shè)計的優(yōu)點如下:

          1.限定了允許同時連接的數(shù)目。
          2.只需要啟動PooledConnectionHandler線程有限次

          這兩句話的涵義將在其后的程序中得到體現(xiàn),下面是 PooledRemoteFileServer 類的結(jié)構(gòu):

          import java.io.*;
          import java.net.*;
          import java.util.*;

          public class PooledRemoteFileServer {
          ??? protected int maxConnections;//定義能同時處理的客戶機(jī)連接的最大數(shù)目???? protected int listenPort;//定義要監(jiān)聽的端口號
          ??? protected ServerSocket serverSocket;

          ??? public PooledRemoteFileServer(int aListenPort, int maxConnections) {
          ??????? listenPort = aListenPort;
          ??????? this.maxConnections = maxConnections;
          ??? }
          ??? public static void main(String[] args) {
          ??? }
          ??? public void setUpHandlers(){//創(chuàng)建數(shù)目為maxConnections的 PooledConnectionHandler
          ??? }
          ??? public void acceptConnections(){//在 ServerSocket 上監(jiān)聽傳入的客戶機(jī)連接,和前面的RemoteFileServer,MultiThreadRemoteFileServer中的監(jiān)聽程序完全一樣
          ??? }
          ??? protected void handleConnection(Socket incomingConnection) {
          ??? }//連接處理程序
          }

          同樣,首先來看main函數(shù)
          public static void main(String[] args) {
          ? PooledRemoteFileServer server = new PooledRemoteFileServer(3000, 3);
          ? server.setUpHandlers();//同前面所有服務(wù)器的main函數(shù)不同,我們先要創(chuàng)建一個連接池,這個池里面有三個可用的connectionHandler
          ? server.acceptConnections();//一旦就緒,就開始監(jiān)聽

          下面我們就來看創(chuàng)建三個connectionHandler的程序如何實現(xiàn):

          public void setUpHandlers(){
          ? for (int i = 0; i < maxConnections; i++) {
          ???? PooledConnectionHandler currentHandler = new PooledConnectionHandler();
          ???? new Thread(currentHandler, "Handler " + i).start();
          ? }
          }

          setUpHandlers() 方法創(chuàng)建maxConnections個PooledConnectionHandler并在新 Thread 中激活它們. PooledConnectionHandler在這里是一個用接口(Runnable)實現(xiàn)的線程體.用實現(xiàn)了Runnable的對象來創(chuàng)建Thread使我們可以在 Thread 調(diào)用 start() 并且可以期望在Runnable上調(diào)用了 run()。也就是說,我們的 PooledConnectionHandler 將等著處理進(jìn)入的連接,每個都在它自己的Thread中進(jìn)行。我們在示例中只創(chuàng)建三個Thread,而且一旦服務(wù)器運(yùn)行,這就不能被改變。

          acceptConnections()方法這里就略去不寫了,看看連接處理程序handleConnection(Socket incomingConnection)

          protected void handleConnection(Socket connectionToHandle) {
          ? PooledConnectionHandler.processRequest(connectionToHandle);
          }

          這里連接處理程序直接調(diào)用了PooledConnectionHandler線程類的類方法processRequest對監(jiān)聽到的連接進(jìn)行處理,顯然這個processRequest是一個靜態(tài)方法.

          PooledRemoteFileServer類中的方法均涉及到一個重要的線程類,PooledConnectionHandler.下面就看看這樣一個用接口實現(xiàn)的類長什么樣:

          public class PooledConnectionHandler implements Runnable {
          ? protected Socket connection;//代表當(dāng)前正在處理的Socket
          ? protected static List pool = new LinkedList();//名為 pool 的靜態(tài) LinkedList 保存需被處理的連接,也就是用LinkedList來模擬一個連接池
          ? public PooledConnectionHandler() {//構(gòu)造函數(shù)
          ? }
          ? public void handleConnection() {//對連接的I/O操作在這里了
          ? }
          ? public static void processRequest(Socket requestToHandle) {//處理客戶連接,將他們加入連接池
          ? }
          ? public void run() {//等待有連接來,來了,就調(diào)handleConnection()處理
          ? }
          }

          可以看出,這個類與多線程Socket那一天的ConnectionHandler非常相似,但不同的是,它帶有處理連接池的手段.

          首先看看要在監(jiān)聽程序中用到的processRequest()方法
          public static void processRequest(Socket requestToHandle) {
          ??? synchronized (pool) {
          ??????? pool.add(pool.size(), requestToHandle);
          ??????? pool.notifyAll();
          ??? }
          }

          這里的requestToHandle就是要處理的客戶連接socket.可以這樣說,processRequest所做的工作就是把客戶連接加入到連接池當(dāng)中.但是要確保在對連接池(Pool)進(jìn)行操作的時候沒有其他的線程干擾,就需要獲取連接池的對象鎖,并使用同步塊,前面所了解有關(guān)synchronized的概念在這里就可以派上用場了.

          那么,既然已經(jīng)保證了我們是唯一“涉水”的人,我們就可以把傳入的 Socket 添加到 LinkedList 的尾端.一旦我們添加了新的連接,我們就可以使用pool.notifyall通知其它正在等待該池的 Thread,連接池的對象鎖解除,現(xiàn)在可用了.從另外一個角度來說,也可以說是通知另外一個正在等待的線程,一些條件已經(jīng)具備了.

          那么這個在等待的線程是什么呢?

          我們來實現(xiàn)PooledConnectionHandler上的run()方法,它將在連接池上等待,并且池中一有連接就處理它,所以是這個要處理連接的線程在等待著呢:

          public void run() {
          ? while (true) {
          ??? synchronized (pool) {
          ????? while (pool.isEmpty()) {
          ??????? try {
          ??????? pool.wait();
          ??????? } catch (InterruptedException e) {return;}
          ????? }
          ????? connection = (Socket) pool.remove(0);//攫取池中的第一個連接,使之成為馬上就要處理的connection
          ??? }
          ? handleConnection();//然后交給handleConnection處理
          ? }
          }

          這個函數(shù)告訴了我們每個PooledConnectionHandler線程主要都在run些什么.顯然,它是要不停的去看連接池中有沒有接入的連接,如果有,馬上處理,因此它在等待"連接池有連接了"這樣一個條件.那么誰來告訴它這個條件滿足了呢,顯然是剛才的processRequest.當(dāng)processRequest發(fā)出通知(pool.notify())的時候,這個條件就滿足了,這時run()中的處理程序就不用再繼續(xù)等待了,就可以馬上去出一個連接進(jìn)行處理.反過來說,在這個條件沒有滿足之前,wait()所在的線程還是要處于阻塞狀態(tài),或者是說停滯狀態(tài).由于同樣要對pool進(jìn)行操作,所以這里也需要使用到同步塊.

          讓我們再次復(fù)習(xí)一下對象鎖的概念.當(dāng) run() 擁有池的互斥鎖時,processRequest() 如何能夠把連接放到池中呢?答案是對池上的 wait() 的調(diào)用釋放鎖,而 wait() 接著就在自己返回之前再次攫取該鎖。這就使得池對象的其它同步代碼可以獲取該鎖。

          最后,我們看看PooledConnectionHandler線程中的handleConnection()方法.跟在多線程服務(wù)器中不同,我們的PooledConnectionHandler有一個 handleConnection() 方法。這個方法的代碼跟非池式的,也就是多線程服務(wù)器中的ConnectionHandler上的 run() 方法的代碼完全一樣。首先,我們把 OutputStream 和 InputStream 分別包裝進(jìn)(用 Socket 上的 getOutputStream() 和 getInputStream())BufferedReader 和 PrintWriter。然后我們逐行讀目標(biāo)文件,就象我們在多線程示例中做的那樣。再一次,我們獲取一些字節(jié)之后就把它們放到本地的 line 變量中,然后寫出到客戶機(jī)。完成讀寫操作之后,我們關(guān)閉 FileReader 和打開的流。

          講到這里,我們可以看到,程序中有兩個類,PooledRemoteFileServer和PooledConnectionHandler.PooledRemoteFileServer并不直接處理連接請求,它只是負(fù)責(zé)監(jiān)聽這些連接,并把他們?nèi)缘竭B接池里面,至于處理的具體環(huán)節(jié),都交給PooledConnectionHandler負(fù)責(zé)了。

          我們的帶有連接池的服務(wù)器研究完了。讓我們回顧一下創(chuàng)建和使用“池版”服務(wù)器的步驟:

          1.創(chuàng)建一個新種類的連接處理程序(我們稱之為 PooledConnectionHandler)來處理池中的連接。
          2.修改服務(wù)器以創(chuàng)建和使用一組 PooledConnectionHandler。

          附:PooledRemoteFileServer.java的源碼

          import java.io.*;
          import java.net.*;
          import java.util.*;

          public class PooledRemoteFileServer {
          ??? protected int maxConnections;
          ??? protected int listenPort;
          ??? protected ServerSocket serverSocket;
          ??? public PooledRemoteFileServer(int aListenPort, int maxConnections) {
          ??????? listenPort = aListenPort;
          ??????? this.maxConnections = maxConnections;
          ??? }
          ??? public void acceptConnections() {
          ??????? try {
          ??????????? ServerSocket server = new ServerSocket(listenPort, 5);
          ??????????? Socket incomingConnection = null;
          ??????????? while (true) {
          ??????????????? incomingConnection = server.accept();
          ??????????????? handleConnection(incomingConnection);
          ??????????? }
          ??????? } catch (BindException e) {
          ??????????? System.out.println("Unable to bind to port " + listenPort);
          ??????? } catch (IOException e) {
          ??????????? System.out.println("Unable to instantiate a ServerSocket on port: " + listenPort);
          ??????? }
          ??? }
          ??? protected void handleConnection(Socket connectionToHandle) {
          ??????? PooledConnectionHandler.processRequest(connectionToHandle);
          ??? }
          ??? public static void main(String[] args) {
          ??????? PooledRemoteFileServer server = new PooledRemoteFileServer(3000, 3);
          ??????? server.setUpHandlers();
          ??????? server.acceptConnections();
          ??? }
          ??? public void setUpHandlers() {
          ??????? for (int i = 0; i < maxConnections; i++) {
          ??????????? PooledConnectionHandler currentHandler = new PooledConnectionHandler();
          ??????????? new Thread(currentHandler, "Handler " + i).start();
          ??????? }
          ??? }
          }

          class PooledConnectionHandler implements Runnable {
          ??? protected Socket connection;
          ??? protected static List pool = new LinkedList();
          ??? public PooledConnectionHandler() {
          ??? }
          ??? public void handleConnection() {
          ??????? try {
          ??????????? PrintWriter streamWriter = new PrintWriter(connection.getOutputStream());
          ??????????? BufferedReader streamReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));

          ??????????? String fileToRead = streamReader.readLine();
          ??????????? BufferedReader fileReader = new BufferedReader(new FileReader(fileToRead));

          ??????????? String line = null;
          ??????????? while ((line = fileReader.readLine()) != null)
          ??????????????? streamWriter.println(line);

          ??????????? fileReader.close();
          ??????????? streamWriter.close();
          ??????????? streamReader.close();
          ??????? } catch (FileNotFoundException e) {
          ??????????? System.out.println("Could not find requested file on the server.");
          ??????? } catch (IOException e) {
          ??????????? System.out.println("Error handling a client: " + e);
          ??????? }
          ??? }
          ??? public static void processRequest(Socket requestToHandle) {
          ??????? synchronized (pool) {
          ??????????? pool.add(pool.size(), requestToHandle);
          ??????????? pool.notifyAll();
          ??????? }
          ??? }
          ??? public void run() {
          ??????? while (true) {
          ??????????? synchronized (pool) {
          ??????????????? while (pool.isEmpty()) {
          ??????????????????? try {
          ??????????????????????? pool.wait();
          ??????????????????? } catch (InterruptedException e) {
          ??????????????????????? return;
          ??????????????????? }
          ??????????????? }
          ??????????????? connection = (Socket) pool.remove(0);
          ??????????? }
          ??????????? handleConnection();
          ??????? }
          ??? }
          }

          posted on 2006-11-22 10:15 OMG 閱讀(160) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           

          <2006年11月>
          2930311234
          567891011
          12131415161718
          19202122232425
          262728293012
          3456789

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          IT風(fēng)云人物

          文檔

          朋友

          相冊

          經(jīng)典網(wǎng)站

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 阜城县| 那坡县| 彰化县| 石景山区| 十堰市| 南漳县| 贵定县| 胶州市| 崇义县| 武冈市| 东丰县| 庆阳市| 民权县| 溧阳市| 赫章县| 济源市| 怀仁县| 临潭县| 宜宾县| 通州区| 横峰县| 顺平县| 谷城县| 河源市| 冀州市| 永顺县| 山阳县| 靖江市| 松溪县| 宜章县| 株洲市| 陆川县| 洪雅县| 三原县| 大竹县| 隆回县| 富锦市| 北票市| 从江县| 金华市| 辛集市|