ホームページ  >  記事  >  Java  >  初心者向けJava学習メモ(9)

初心者向けJava学習メモ(9)

黄舟
黄舟オリジナル
2016-12-20 13:55:23997ブラウズ


マルチスレッドを実装するためにインターフェイスを使用することと、スレッド本体を構築するためにクラスを使用することの違いを突然発見しました。以前は、クラスを使用してスレッド本体を構築する場合、このクラスを使用する必要があるようです。 MyThread.thread1=New MyThread() などのスレッド オブジェクトを定義し、スレッド本体を作成するためにインターフェイスを使用する場合は、Thread thread1=new Thread(MyThread) などの Thread クラスを使用するだけで済みます。数日前に述べたマルチスレッド Socket にそれが反映されています

過去の絶え間ない努力により、当初の未完成の作業を継続し、Socket の接続プール バージョンに向けて正式に移行することができました。マルチスレッド サーバー MultiThreadRemoteFileServer を作成しました。これは、数日間の内容に依存します。要約すると、接続を待機している各クライアントに新しいスレッドを使用し、クライアントが接続を申請するたびに 1 つずつ割り当てます。 、新しい ConnectionHandler が新しいスレッドで作成されます (注: インターフェイスによって構築されたスレッド本体を使用します)。これは、システム全体で 12 個のスレッドが実行される可能性があることを意味します。明らかに、システムのオーバーヘッドはその数に応じて増加し続けます。接続するクライアントの数が増加すると、システムがそれに耐えられなくなる可能性があるため、接続するクライアントの数を制限し、効率を向上させる方法を見つける必要があります。

その場合の解決策は、サーバーの起動時に一定数の PooledConnectionHandler を作成し、残りの処理を PooledConnectionHandler に任せることです。この設計の利点は次のとおりです:

1. 許可される同時接続数を制限します。
2. PooledConnectionHandler スレッドを開始する必要があるのは限られた回数だけです

これら 2 つの文の意味は、後続のプログラムに反映されます。以下は 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(){//RemoteFileServer および MultiThreadRemoteFileServer で以前のリッスン プログラムとまったく同じように、ServerSocket で着信クライアント接続をリッスンします
}
protected void handleConnection(Socket incomingConnection) {
}//接続ハンドラー
}

同様に、最初にメイン関数を見てみましょう
public static void main(String[] args) {
PooledRemoteFileServer server = new PooledRemoteFileServer(3000, 3);
server.setUpHandlers(); //以前のすべてのサーバーのメイン関数とは異なり、最初にこのプールに 3 つの利用可能な connectionHandler を作成する必要があります
server.acceptConnections();//準備ができたら、リスニングを開始します

以下の作成を見てみましょう 3 つの 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 でそれらをアクティブ化します。これは、インターフェイスで実装されたスレッド本体です。 (Runnable)。スレッドを作成するために Runnable オブジェクトを実装して、スレッド上で start() を呼び出し、Runnable 上で run() が呼び出されるようにします。つまり、PooledConnectionHandler は、それぞれ独自のスレッドで着信接続の処理を待機します。この例では 3 つのスレッドのみを作成しますが、これはサーバーの実行後に変更することはできません。

acceptConnections() メソッドはここでは省略します。接続ハンドラー handleConnection(Socket incomingConnection)

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

接続ハンドラーを見てみましょう。 PooledConnectionHandler スレッド クラスのクラス メソッド processRequest は、監視対象の接続を処理するために直接呼び出されます。この processRequest は静的メソッドです。PooledRemoteFileServer クラスのメソッドはすべて、PooledConnectionHandler という重要なスレッド クラスに関係します。 one インターフェイスで実装されたクラスは次のようになります:

public class PooledConnectionHandlerimplements Runnable {
protected Socket connection;//現在処理中の Socket を表します
protected static List pool = new LinkedList();//Static LinkedList 名前付きプール保存 処理する必要がある接続は、LinkedList を使用して接続プールをシミュレートすることです
public PooledConnectionHandler() {//Constructor
}
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 は、処理対象の顧客です。 processRequest は、顧客の接続を接続プールに追加することですが、接続プール (Pool. )、接続プールのオブジェクト ロックを取得する必要があります。同期ブロックを使用すると、前に学んだ同期の概念が役に立ちます。

これで、私たちだけであることを確認できました。 wading" の場合、受信ソケットを LinkedList の末尾に追加できます。新しい接続を追加したら、pool.notifyall を使用して、プールを待機している他のスレッドに通知できます。接続プールのオブジェクト ロックが解放され、別の観点から見ると、いくつかの条件が満たされたことを別の待機中のスレッドに通知するためのものとも言えます

それでは、この待機中のスレッドとは何でしょうか? PooledConnectionHandler に run() メソッドを実装しましょう。接続プールで待機し、プール内で接続が確立されるとすぐに処理するため、接続を処理するスレッドが待機します:

public void run() {
while (true) {
synchronized (pool) {
while (pool.isEmpty()) {
try {
pool.wait();
} catch (InterruptedException e) {return;}
}
connection = (Socket) pool.remove(0);//プール内の最初の接続をすぐに作成します 処理される接続
}
handleConnection();//その後、処理のために handleConnection に渡します
}
}

この関数は、各 PooledConnectionHandler スレッドが主に実行しているものを明らかにします。接続プールに受信接続があるかどうかを確認し、存在する場合はすぐに処理するため、「接続プールに接続がある」という状態を待機します。この状態であることを誰が通知するでしょうか。 processRequest が通知 (pool.notify()) を発行すると、この条件が満たされ、run() のハンドラーはすぐに作成できるようになります。一方、この条件が満たされる前は、wait() が配置されているスレッドはブロック状態または停滞状態になります。プールも操作する必要があるため、ブロックは同期されます。ここでも使用する必要があります。

オブジェクトのロックをもう一度見てみましょう。 run() がプールのミューテックスを所有している場合、processRequest() はどのように接続をプールに入れることができるでしょうか。答えは、プール上で wait() を呼び出すとロックが解放され、wait() は自身を返す前に再度ロックを取得するということです。これにより、プール オブジェクト上の他の同期コードがロックを取得できるようになります。

最後に、PooledConnectionHandler スレッドの handleConnection() メソッドを見てみましょう。マルチスレッド サーバーとは異なり、PooledConnectionHandler には handleConnection() メソッドがあります。このメソッドのコードは、プールされていないマルチスレッド サーバーの ConnectionHandler の run() メソッドのコードとまったく同じです。まず、OutputStream と InputStream を (Socket の getOutputStream() と getInputStream() を使用して) BufferedReader と PrintWriter にそれぞれラップします。次に、マルチスレッドの例で行ったのと同じように、ターゲット ファイルを 1 行ずつ読み取ります。もう一度、いくつかのバイトを取得し、それらをローカルの行変数に入れて、クライアントに書き込みます。読み取りおよび書き込み操作が完了したら、FileReader と開いているストリームを閉じます。

そういえば、プログラムには PooledRemoteFileServer と PooledConnectionHandler という 2 つのクラスがあることがわかります。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("ポートにバインドできません " + listenPort);
} catch (IOException e) {
System.out.println("ポートで ServerSocket をインスタンス化できません: " + listenPort);
}
}
protected void handleConnection(Socket connectionToHandle) {
PooledConnectionHandler.processRequest (connectionToHandle);
}
public static void main(String[] args) {
PooledRemoteFileServer サーバー = 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 は 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("サーバー上で要求されたファイルが見つかりませんでした。");
} catch (IOException e) {
System.out.println("クライアント処理エラー: " + 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の备忘れ录(九)の内容、より多くの関連内容请关注PHP中文网(www.php.cn)!


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。