91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java如何創建多線程的服務器

發布時間:2022-01-10 09:17:37 來源:億速云 閱讀:123 作者:iii 欄目:編程語言

這篇“Java如何創建多線程的服務器”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Java如何創建多線程的服務器”文章吧。

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

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

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

這兩句話的涵義將在其后的程序中得到體現,下面是 PooledRemoteFileServer 類的結構:


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 static void main(String[] args) {
  }
  public void setUpHandlers(){//創建數目為maxConnections的 PooledConnectionHandler
  }
  public void acceptConnections(){//在 ServerSocket 上監聽傳入的客戶機連接,和前面的RemoteFileServer,MultiThreadRemoteFileServer中的監聽程序完全一樣
  }
  protected void handleConnection(Socket incomingConnection) {
  }//連接處理程序
}

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

下面我們就來看創建三個connectionHandler的程序如何實現:

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

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

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

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

這里連接處理程序直接調用了PooledConnectionHandler線程類的類方法processRequest對監聽到的連接進行處理,顯然這個processRequest是一個靜態方法.

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

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

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

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

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

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

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

我們來實現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處理
  }
}

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

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

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

講到這里,我們可以看到,程序中有兩個類,PooledRemoteFileServer和PooledConnectionHandler.PooledRemoteFileServer并不直接處理連接請求,它只是負責監聽這些連接,并把他們仍到連接池里面,至于處理的具體環節,都交給PooledConnectionHandler負責了。


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

1.創建一個新種類的連接處理程序(我們稱之為 PooledConnectionHandler)來處理池中的連接。
2.修改服務器以創建和使用一組 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();
  }
  }
}

以上就是關于“Java如何創建多線程的服務器”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

峨山| 文成县| 彭阳县| 玉环县| 武汉市| 定西市| 南木林县| 雅安市| 洞头县| 正安县| 绩溪县| 皮山县| 祥云县| 佛山市| 大关县| 澄城县| 任丘市| 鹤壁市| 夏河县| 子洲县| 专栏| 明光市| 建昌县| 乡城县| 日土县| 新兴县| 遂平县| 永康市| 武邑县| 板桥市| 韶山市| 遂川县| 南投市| 天全县| 珲春市| 辽阳市| 城市| 三台县| 郎溪县| 同德县| 遂昌县|