I suddenly discovered the difference between using interfaces to implement multi-threading and using classes to construct thread bodies. I didn’t seem to pay much attention to it before. When using classes to construct thread bodies, you need to use this class to define thread objects, such as MyThread. thread1=New MyThread(), and when using the interface to create a thread body, you only need to use the Thread class, such as Thread thread1=new Thread(MyThread). This is all in the multi-threaded Socket mentioned a few days ago. It is reflected.
The unremitting efforts in the past have enabled me to continue the original unfinished work and officially move towards the connection pool version of Socket.
Let’s review how we created the multi-threaded server MultiThreadRemoteFileServer. This depends on the previous A few days of content. To summarize, it is to use a new thread for each client waiting for a connection, and allocate one to one. Whenever a client applies for a connection, a new ConnectionHandler is created in a new Thread (note: use The thread body constructed by the interface). This means that there may be a dozen Threads running in the entire system. Obviously, the system overhead will continue to increase as the number of connected clients increases. We cannot but consider that the overhead increases to a certain extent. Sometimes the system may not be able to bear it. Therefore, we have to find a way to limit the number of connected clients and improve the efficiency of the server.
Then the solution is: on the server side, we create a certain number of PooledConnectionHandlers when the server starts. Put the incoming connection into a connection pool and let the PooledConnectionHandler take care of the rest. The client program does not need to be modified at all. The advantages of this design are as follows:
1. Limits the number of simultaneous connections allowed.
2. You only need to start the PooledConnectionHandler thread a limited number of times
The meaning of these two sentences will be reflected in the subsequent program. The following is the structure of the PooledRemoteFileServer class:
import java.io.*;
import java.net. *;
import java.util.*;
public class PooledRemoteFileServer {
PRotected int maxConnections;//Define the maximum number of client connections that can be processed simultaneously protected int listenPort;//Define the port number to be listened to
protected ServerSocket serverSocket ;
public PooledRemoteFileServer(int aListenPort, int maxConnections) {
listenPort = aListenPort;
this.maxConnections = maxConnections;
}
public static void main(String[] args) {
}
public void setUpHandlers(){// Create a PooledConnectionHandler with a number of maxConnections
}
public void acceptConnections(){//Listen to incoming client connections on ServerSocket, exactly the same as the previous listening programs in RemoteFileServer and MultiThreadRemoteFileServer
}
protected void handleConnection(Socket incomingConnection) {
}//Connection handler
}
Similarly, let’s look at the main function first
public static void main(String[] args) {
PooledRemoteFileServer server = new PooledRemoteFileServer(3000, 3);
server.setUpHandlers(); //Different from the main function of all previous servers, we first need to create a connection pool. There are three available connectionHandlers in this pool
server.acceptConnections();//Once ready, start listening
Let’s look at the creation below How to implement the three connectionHandler programs:
public void setUpHandlers(){
for (int i = 0; i < maxConnections; i++) {
PooledConnectionHandler currentHandler = new PooledConnectionHandler();
new Thread(currentHandler, "Handler " + i).start();
}
}
setUpHandlers() method creates maxConnections PooledConnectionHandlers and activates them in a new Thread. PooledConnectionHandler here is a thread body implemented with an interface (Runnable). Implemented with Runnable Object to create a Thread so that we can call start() on the Thread and expect run() to be called on the Runnable. That is, our PooledConnectionHandler will wait to handle incoming connections, each in its own Thread. We only create three Threads in our example, and this cannot be changed once the server is running.
acceptConnections() method will be omitted here. Take a look at the connection handler handleConnection(Socket incomingConnection)
protected void handleConnection(Socket connectionToHandle) {
PooledConnectionHandler.processRequest(connectionToHandle);
}
Here is the connection handler The class method processRequest of the PooledConnectionHandler thread class is directly called to process the monitored connection. Obviously, this processRequest is a static method.
The methods in the PooledRemoteFileServer class all involve an important thread class, PooledConnectionHandler. Let’s take a look at such one What does the class implemented with the interface look like:
public class PooledConnectionHandler implements Runnable {
protected Socket connection;//Represents the Socket currently being processed
protected static List pool = new LinkedList();//Static LinkedList named pool Save The connection that needs to be processed is to use LinkedList to simulate a connection pool
public PooledConnectionHandler() {//Constructor
}
public void handleConnection() {//The I/O operation on the connection is here
}
public static void processRequest(Socket requestToHandle) {//Process customer connections and add them to the connection pool
}
public void run() {//Wait for a connection to come. When it comes, call handleConnection() to handle it
}
}
It can be seen that this class is very similar to the ConnectionHandler of the multi-threaded Socket day, but the difference is that it has a means to handle the connection pool.
First look at the processRequest() method to be used in the listener
public static void processRequest(Socket requestToHandle) {
synchronized (pool) {
pool.add(pool.size(), requestToHandle);
pool.notifyAll();
}
}
The requestToHandle here is the customer to be processed Connect the socket. It can be said that what processRequest does is to add the customer connection to the connection pool. But to ensure that there is no interference from other threads when operating the connection pool (Pool), you need to obtain the object lock of the connection pool. , and using synchronized blocks, the concept of synchronized that we learned earlier can come in handy here.
So, now that we have ensured that we are the only ones "wading", we can add the incoming Socket to The tail end of LinkedList. Once we add a new connection, we can use pool.notifyall to notify other Threads that are waiting for the pool. The object lock of the connection pool is released and is now available. From another perspective, it can also be said It is to notify another waiting thread that some conditions have been met.
So what is this waiting thread?
Let’s implement the run() method on PooledConnectionHandler, which will wait on the connection pool, and in the pool Process it as soon as there is a connection, so the thread to process the connection is waiting:
public void run() {
while (true) {
synchronized (pool) {
while (pool.isEmpty()) {
try {
pool.wait();
} catch (InterruptedException e) {return;}
}
connection = (Socket) pool.remove(0);//Get the first connection in the pool and make it immediately The connection to be processed
}
handleConnection();//Then hand it over to handleConnection for processing
}
}
This function tells us what each PooledConnectionHandler thread is mainly running. Obviously, it has to keep going Check whether there is an incoming connection in the connection pool. If there is, process it immediately, so it is waiting for the condition "the connection pool has a connection". Then who will tell it that this condition is met? It is obviously the processRequest just now. When When processRequest issues a notification (pool.notify()), this condition is met. At this time, the handler in run() no longer has to wait, and can immediately create a connection for processing. On the other hand, in Before this condition is met, the thread where wait() is located will still be in a blocked state, or in a stagnant state. Since the pool also needs to be operated, synchronized blocks also need to be used here.
Let us review object locks again Concept. When run() owns the pool's mutex, how can processRequest() put the connection into the pool? The answer is that a call to wait() on the pool releases the lock, and wait() then grabs the lock again before returning itself. This allows other synchronization code on the pool object to acquire the lock.
Finally, let’s look at the handleConnection() method in the PooledConnectionHandler thread. Unlike in multi-threaded servers, our PooledConnectionHandler has a handleConnection() method. The code of this method is exactly the same as the run() method on the ConnectionHandler in a non-pooled, multi-threaded server. First, we wrap the OutputStream and InputStream into (using getOutputStream() and getInputStream() on the Socket) a BufferedReader and a PrintWriter respectively. We then read the target file line by line, just like we did in the multi-threaded example. Once again, we get some bytes, put them into a local line variable, and write them out to the client. After completing the read and write operations, we close the FileReader and the open stream.
Speaking of which, we can see that there are two classes in the program, PooledRemoteFileServer and PooledConnectionHandler. PooledRemoteFileServer does not directly process connection requests. It is only responsible for monitoring these connections and returning them to the connection pool. As for the specific processing All aspects are handed over to PooledConnectionHandler.
Our server with connection pool has been studied. Let's review the steps for creating and using a "pooled" server:
1. Create a new kind of connection handler (let's call it PooledConnectionHandler) to handle pooled connections.
2. Modify the server to create and use a set of PooledConnectionHandlers.
Attached: the source code of 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的备忘录(九)的内容,更多相关内容请关注PHP中文网(m.sbmmt.com)!