Java中的多线程服务器
时间:2020-01-09 10:36:12 来源:igfitidea点击:
本文介绍了用Java实现的简单多线程服务器。该代码基于单线程服务器上文本中描述的单线程服务器。主要区别在于服务器循环。与其在接受客户端连接的同一线程中处理传入请求,不如将连接切换到将处理该请求的工作线程。
注意:此代码使用"每个连接线程"设计,我们大多数人最初认为这比线程池服务器的效率低。但是,请阅读此博客文章,然后再三思:编写Java多线程服务器,旧有的是新的。
这是服务器循环在多线程版本中的外观:
while(! isStopped()){ Socket clientSocket = null; try { clientSocket = this.serverSocket.accept(); } catch (IOException e) { if(isStopped()) { System.out.println("Server Stopped.") ; return; } throw new RuntimeException( "Error accepting client connection", e); } new Thread( new WorkerRunnable( clientSocket, "Multithreaded Server") ).start(); }
从单线程服务器到此处的循环中唯一的变化是粗体代码:
new Thread( new WorkerRunnable( clientSocket, "Multithreaded Server") ).start();
与其在接受客户端连接的同一线程中处理传入请求,不如将连接切换到处理该请求的工作线程。这样,侦听传入请求的线程会在serverSocket.accept()
调用中花费尽可能多的时间。这样,由于侦听线程不在accept()
调用之内,从而使拒绝访问服务器的客户端的风险降到最低。
这是WorkerRunnable
类的代码,该代码传递给工作线程构造函数:
package servers; import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; import java.net.Socket; /** */ public class WorkerRunnable implements Runnable{ protected Socket clientSocket = null; protected String serverText = null; public WorkerRunnable(Socket clientSocket, String serverText) { this.clientSocket = clientSocket; this.serverText = serverText; } public void run() { try { InputStream input = clientSocket.getInputStream(); OutputStream output = clientSocket.getOutputStream(); long time = System.currentTimeMillis(); output.write(("HTTP/1.1 200 OK\n\nWorkerRunnable: " + this.serverText + " - " + time + "").getBytes()); output.close(); input.close(); System.out.println("Request processed: " + time); } catch (IOException e) { //report exception somewhere. e.printStackTrace(); } } }
多线程服务器的优势
与单线程服务器相比,多线程服务器的优点总结如下:
- 在
accept()
调用之外花费的时间更少。 - 长时间运行的客户端请求不会阻止整个服务器
如前所述,调用serverSocket.accept()
的线程在此方法调用中花费的时间越多,服务器的响应速度就越快。只有当侦听线程在" accept()"调用内部时,客户端才能连接到服务器。否则,客户只会得到一个错误。
在单线程服务器中,长时间运行的请求可能会使服务器长时间不响应。对于多线程服务器,情况并非如此,除非长时间运行的请求占用了所有CPU时间和/或者网络带宽。
多线程服务器代码
这是MultiThreadedServer的完整代码:
package servers; import java.net.ServerSocket; import java.net.Socket; import java.io.IOException; public class MultiThreadedServer implements Runnable{ protected int serverPort = 8080; protected ServerSocket serverSocket = null; protected boolean isStopped = false; protected Thread runningThread= null; public MultiThreadedServer(int port){ this.serverPort = port; } public void run(){ synchronized(this){ this.runningThread = Thread.currentThread(); } openServerSocket(); while(! isStopped()){ Socket clientSocket = null; try { clientSocket = this.serverSocket.accept(); } catch (IOException e) { if(isStopped()) { System.out.println("Server Stopped.") ; return; } throw new RuntimeException( "Error accepting client connection", e); } new Thread( new WorkerRunnable( clientSocket, "Multithreaded Server") ).start(); } System.out.println("Server Stopped.") ; } private synchronized boolean isStopped() { return this.isStopped; } public synchronized void stop(){ this.isStopped = true; try { this.serverSocket.close(); } catch (IOException e) { throw new RuntimeException("Error closing server", e); } } private void openServerSocket() { try { this.serverSocket = new ServerSocket(this.serverPort); } catch (IOException e) { throw new RuntimeException("Cannot open port 8080", e); } } }
这是运行它的代码:
MultiThreadedServer server = new MultiThreadedServer(9000); new Thread(server).start(); try { Thread.sleep(20 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Stopping Server"); server.stop();
服务器运行时,我们可以使用普通的Web浏览器访问它。使用地址http:// localhost:9000 /