這篇“Java如何創(chuàng)建多線程的服務(wù)器”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“Java如何創(chuàng)建多線程的服務(wù)器”文章吧。
創(chuàng)新互聯(lián)建站是專業(yè)的拱墅網(wǎng)站建設(shè)公司,拱墅接單;提供成都網(wǎng)站建設(shè)、成都網(wǎng)站制作,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行拱墅網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!回顧一下我們是如何創(chuàng)建多線程的服務(wù)器MultiThreadRemoteFileServer的,這得看看前幾天的內(nèi)容了.概括起來(lái),就是為每個(gè)等待連接的客戶new一個(gè)線程使用,來(lái)一個(gè)分配一個(gè).每當(dāng)有客戶機(jī)申請(qǐng)一個(gè)連接時(shí)都在一個(gè)新 Thread 中創(chuàng)建一個(gè)新 ConnectionHandler(注:使用接口構(gòu)造的線程體).這意味著可能有一打 Thread在整個(gè)系統(tǒng)中運(yùn)行著.顯然,系統(tǒng)的開(kāi)銷會(huì)因?yàn)檫B接客戶的數(shù)目的增長(zhǎng)而不斷增加.我們不能夠不考慮到開(kāi)銷增加到一定程度的時(shí)候系統(tǒng)會(huì)承受不住的可能.因此,得想個(gè)辦法限制連接客戶的數(shù)量,提高服務(wù)器的效率.
那么解決的方案是:在服務(wù)器端,我們?cè)诜?wù)器啟動(dòng)時(shí)創(chuàng)建一定數(shù)量的PooledConnectionHandler,我們把進(jìn)入的連接放入一個(gè)連接池中并讓PooledConnectionHandler 打理剩下的事情.客戶端的程序完全不用修改,這樣設(shè)計(jì)的優(yōu)點(diǎn)如下:
1.限定了允許同時(shí)連接的數(shù)目。
2.只需要啟動(dòng)PooledConnectionHandler線程有限次
這兩句話的涵義將在其后的程序中得到體現(xiàn),下面是 PooledRemoteFileServer 類的結(jié)構(gòu):
import Java.io.*;
import java.NET.*;
import java.util.*;
public class PooledRemoteFileServer {
protected int maxConnections;//定義能同時(shí)處理的客戶機(jī)連接的大數(shù)目 protected int listenPort;//定義要監(jiān)聽(tīng)的端口號(hào)
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)聽(tīng)傳入的客戶機(jī)連接,和前面的RemoteFileServer,MultiThreadRemoteFileServer中的監(jiān)聽(tīng)程序完全一樣
}
protected void handleConnection(Socket incomingConnection) {
}//連接處理程序
}
同樣,首先來(lái)看main函數(shù)
public static void main(String[] args) {
PooledRemoteFileServer server = new PooledRemoteFileServer(3000, 3);
server.setUpHandlers();//同前面所有服務(wù)器的main函數(shù)不同,我們先要?jiǎng)?chuàng)建一個(gè)連接池,這個(gè)池里面有三個(gè)可用的connectionHandler
server.acceptConnections();//一旦就緒,就開(kāi)始監(jiān)聽(tīng)
下面我們就來(lái)看創(chuàng)建三個(gè)connectionHandler的程序如何實(shí)現(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個(gè)PooledConnectionHandler并在新 Thread 中激活它們. PooledConnectionHandler在這里是一個(gè)用接口(Runnable)實(shí)現(xiàn)的線程體.用實(shí)現(xiàn)了Runnable的對(duì)象來(lái)創(chuàng)建Thread使我們可以在 Thread 調(diào)用 start() 并且可以期望在Runnable上調(diào)用了 run()。也就是說(shuō),我們的 PooledConnectionHandler 將等著處理進(jìn)入的連接,每個(gè)都在它自己的Thread中進(jìn)行。我們?cè)谑纠兄粍?chuàng)建三個(gè)Thread,而且一旦服務(wù)器運(yùn)行,這就不能被改變。
acceptConnections()方法這里就略去不寫了,看看連接處理程序handleConnection(Socket incomingConnection)
protected void handleConnection(Socket connectionToHandle) {
PooledConnectionHandler.processRequest(connectionToHandle);
}
這里連接處理程序直接調(diào)用了PooledConnectionHandler線程類的類方法processRequest對(duì)監(jiān)聽(tīng)到的連接進(jìn)行處理,顯然這個(gè)processRequest是一個(gè)靜態(tài)方法.
PooledRemoteFileServer類中的方法均涉及到一個(gè)重要的線程類,PooledConnectionHandler.下面就看看這樣一個(gè)用接口實(shí)現(xiàn)的類長(zhǎng)什么樣:
public class PooledConnectionHandler implements Runnable {
protected Socket connection;//代表當(dāng)前正在處理的Socket
protected static List pool = new LinkedList();//名為 pool 的靜態(tài) LinkedList 保存需被處理的連接,也就是用LinkedList來(lái)模擬一個(gè)連接池
public PooledConnectionHandler() {//構(gòu)造函數(shù)
}
public void handleConnection() {//對(duì)連接的I/O操作在這里了
}
public static void processRequest(Socket requestToHandle) {//處理客戶連接,將他們加入連接池
}
public void run() {//等待有連接來(lái),來(lái)了,就調(diào)handleConnection()處理
}
}
可以看出,這個(gè)類與多線程Socket那一天的ConnectionHandler非常相似,但不同的是,它帶有處理連接池的手段.
首先看看要在監(jiān)聽(tīng)程序中用到的processRequest()方法
public static void processRequest(Socket requestToHandle) {
synchronized (pool) {
pool.add(pool.size(), requestToHandle);
pool.notifyAll();
}
}
這里的requestToHandle就是要處理的客戶連接socket.可以這樣說(shuō),processRequest所做的工作就是把客戶連接加入到連接池當(dāng)中.但是要確保在對(duì)連接池(Pool)進(jìn)行操作的時(shí)候沒(méi)有其他的線程干擾,就需要獲取連接池的對(duì)象鎖,并使用同步塊,前面所了解有關(guān)synchronized的概念在這里就可以派上用場(chǎng)了.
那么,既然已經(jīng)保證了我們是唯一“涉水”的人,我們就可以把傳入的 Socket 添加到 LinkedList 的尾端.一旦我們添加了新的連接,我們就可以使用pool.notifyall通知其它正在等待該池的 Thread,連接池的對(duì)象鎖解除,現(xiàn)在可用了.從另外一個(gè)角度來(lái)說(shuō),也可以說(shuō)是通知另外一個(gè)正在等待的線程,一些條件已經(jīng)具備了.
那么這個(gè)在等待的線程是什么呢?
我們來(lái)實(shí)現(xiàn)PooledConnectionHandler上的run()方法,它將在連接池上等待,并且池中一有連接就處理它,所以是這個(gè)要處理連接的線程在等待著呢:
public void run() {
while (true) {
synchronized (pool) {
while (pool.isEmpty()) {
try {
pool.wait();
} catch (InterruptedException e) {return;}
}
connection = (Socket) pool.remove(0);//攫取池中的第一個(gè)連接,使之成為馬上就要處理的connection
}
handleConnection();//然后交給handleConnection處理
}
}
這個(gè)函數(shù)告訴了我們每個(gè)PooledConnectionHandler線程主要都在run些什么.顯然,它是要不停的去看連接池中有沒(méi)有接入的連接,如果有,馬上處理,因此它在等待"連接池有連接了"這樣一個(gè)條件.那么誰(shuí)來(lái)告訴它這個(gè)條件滿足了呢,顯然是剛才的processRequest.當(dāng)processRequest發(fā)出通知(pool.notify())的時(shí)候,這個(gè)條件就滿足了,這時(shí)run()中的處理程序就不用再繼續(xù)等待了,就可以馬上去出一個(gè)連接進(jìn)行處理.反過(guò)來(lái)說(shuō),在這個(gè)條件沒(méi)有滿足之前,wait()所在的線程還是要處于阻塞狀態(tài),或者是說(shuō)停滯狀態(tài).由于同樣要對(duì)pool進(jìn)行操作,所以這里也需要使用到同步塊.
讓我們?cè)俅螐?fù)習(xí)一下對(duì)象鎖的概念.當(dāng) run() 擁有池的互斥鎖時(shí),processRequest() 如何能夠把連接放到池中呢?答案是對(duì)池上的 wait() 的調(diào)用釋放鎖,而 wait() 接著就在自己返回之前再次攫取該鎖。這就使得池對(duì)象的其它同步代碼可以獲取該鎖。
最后,我們看看PooledConnectionHandler線程中的handleConnection()方法.跟在多線程服務(wù)器中不同,我們的PooledConnectionHandler有一個(gè) handleConnection() 方法。這個(gè)方法的代碼跟非池式的,也就是多線程服務(wù)器中的ConnectionHandler上的 run() 方法的代碼完全一樣。首先,我們把 OutputStream 和 InputStream 分別包裝進(jìn)(用 Socket 上的 getOutputStream() 和 getInputStream())BufferedReader 和 PrintWriter。然后我們逐行讀目標(biāo)文件,就象我們?cè)诙嗑€程示例中做的那樣。再一次,我們獲取一些字節(jié)之后就把它們放到本地的 line 變量中,然后寫出到客戶機(jī)。完成讀寫操作之后,我們關(guān)閉 FileReader 和打開(kāi)的流。
講到這里,我們可以看到,程序中有兩個(gè)類,PooledRemoteFileServer和PooledConnectionHandler.PooledRemoteFileServer并不直接處理連接請(qǐng)求,它只是負(fù)責(zé)監(jiān)聽(tīng)這些連接,并把他們?nèi)缘竭B接池里面,至于處理的具體環(huán)節(jié),都交給PooledConnectionHandler負(fù)責(zé)了。
我們的帶有連接池的服務(wù)器研究完了。讓我們回顧一下創(chuàng)建和使用“池版”服務(wù)器的步驟:
1.創(chuàng)建一個(gè)新種類的連接處理程序(我們稱之為 PooledConnectionHandler)來(lái)處理池中的連接。
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();
}
}
}
以上就是關(guān)于“Java如何創(chuàng)建多線程的服務(wù)器”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道。