我们完成了这个 小型Tomcat 基本功能,但是他处理请求还是 一个一个的执行,并不能做到并行处理。 我们仿照Tomcat的思路来进行 一比一精准优化。
首先看一下我们的JxdHttpConnector 有什么改进,他可以理解成一个快递站领导,统一指挥JxdHttpProcessor 进行 工作。
JxdHttpConnector引入一个队列池,每接到一个请求,就冲队列池中取出来,执行这个请求,执行完之后再放回队列池中,继续等待下一个处理。
import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayDeque; import java.util.Deque; public class JxdHttpConnector implements Runnable { int minProcessors = 3; int maxProcessors = 10; int curProcessors = 0; //存放多个processor的池子 Deque<JxdHttpProcessor> processorDeque = new ArrayDeque<>(); @Override public void run() { ServerSocket serverSocket = null; int port = 8080; try { serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); } catch (IOException e) { e.printStackTrace(); System.exit(1); } //初始化池子 最开始三个 initProcessorDeque(); while (true) { Socket socket = null; try { //这是单线程 一个请求一个请求获取socket socket = serverSocket.accept(); //得到一个新的processor,这个processor从池中获取(池中有可能新建) JxdHttpProcessor processor = createProcessor(); if (processor == null) { socket.close(); continue; } processor.assign(socket); } catch (Exception e) { e.printStackTrace(); } } } public void start() { Thread thread = new Thread(this); thread.start(); } //从池子中获取一个processor,如果池子为空且小于最大限制,则新建一个 private JxdHttpProcessor createProcessor() { synchronized (processorDeque) { if (processorDeque.size() > 0) { return processorDeque.pop(); } if (curProcessors < maxProcessors) { return newProcessor(); } else { return null; } } } private void initProcessorDeque(){ for (int i = 0; i < minProcessors; i++) { JxdHttpProcessor processor = new JxdHttpProcessor(this); processor.start(); processorDeque.push(processor); } curProcessors = minProcessors; } private JxdHttpProcessor newProcessor() { JxdHttpProcessor jxdHttpProcessor = new JxdHttpProcessor(this); jxdHttpProcessor.start(); processorDeque.push(jxdHttpProcessor); curProcessors++; return processorDeque.pop(); } public void recycle(JxdHttpProcessor processor) { processorDeque.push(processor); } }
processorDeque这就是队列池,刚开始的时候 会创建三个,随着业务访问了增加 最多增加10个 ,
你们发现了吗 JxdHttpProcessor 为啥要.start()多线程进行处理,因为 你 虽然引入队列池但是还是不能 解决并行处理问题,所以要让每一个真正的执行者(员工)。进行并行处理。
JxdHttpProcessor 代码:
public class JxdHttpProcessor implements Runnable { boolean available = false; Socket socket; JxdHttpConnector connector; public JxdHttpProcessor(JxdHttpConnector connector) { this.connector = connector; } private void process(Socket socket) { //服务器循环等待请求并处理 try { Thread.sleep(3000); } catch (InterruptedException e1) { e1.printStackTrace(); } InputStream input = null; OutputStream output = null; try { input = socket.getInputStream(); output = socket.getOutputStream(); // create Request object and parse JxdRequest request = new JxdRequest(input); request.parse(); // create Response object JxdResponse response = new JxdResponse(output); if (request.getUri().startsWith("/servlet/")) { //加载动态资源 JxdServletProcessor jxdServletProcessor = new JxdServletProcessor(); jxdServletProcessor.process(request, response); } else { //加载静态资源 StaticResourceProcessor staticResourceProcessor = new StaticResourceProcessor(); staticResourceProcessor.process(request, response); } //因为是多线程所以只能交给httpProcessor 来关闭 socket.close(); } catch (Exception ea) { ea.printStackTrace(); } } @Override public void run() { while (true) { // 等待socket分配过来 Socket socket = await(); if (socket == null) continue; // 处理请求 process(socket); // 回收processor,员工归队 connector.recycle(this); } } public void start() { Thread thread = new Thread(this); thread.start(); } private synchronized Socket await() { // 等待connector提供一个新的socket while (!available) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 获得这个新的Socket Socket socket = this.socket; //设置标志为false available = false; //通知另外的线程 notifyAll(); return (socket); } public synchronized void assign(Socket socket) { // 等待connector提供一个新的socket while (available) { try { wait(); } catch (InterruptedException e) { } } // 获取到这个新的Socket this.socket = socket; // 把标志设置回去 available = true; //通知另外的线程 notifyAll(); } }
JxdHttpProcessor 真正的执行者 实现了 Runnable 接口 同时引入了 await()和assign()方法和available 标识。 先说await()方法 ,available 默认为false 也就是线程启动的时候进入 等待状态,一直等,等谁呢 他在等待一个指令,就类似于 员工快递站工作,等来了快递 才工作 没有快递 就休息。
在说一下 assign()方法,他的入参是Socket ,表示 快递来了 ,因为available 默认为false所以他会继续走 ,把标志available 默认为true 然后 通知await()中等待的 员工要开始工作了 。
这就是 形成了一套 运行 机制,我通知你干活,你干完活之后 告诉我 ,我们在02那篇文章的时候是这样的,JxdHttpConnector 领导一直紧跟着JxdHttpProcessor 员工,直到员工干完活,一个领导盯着一个员工很累的,现在是 这个领导 统一指挥一个 团队,员工自己干完活之后反馈给领导。
socket.close(); 还记得这个吗。之前是 有JxdHttpConnector 来关闭的,现在由 员工JxdHttpProcessor来关闭了,为啥 因为领导 一致盯着 员工直到 结束,但是现在 盯不住了 ,只能员工自己 才知道什么时候结束 。
备注:其他类不展示 基本每改动。文章来源:https://www.toymoban.com/news/detail-853664.html
看一下运行结果吧。 文章来源地址https://www.toymoban.com/news/detail-853664.html
public class JxdHttpServer { public static final String WEB_ROOT = System.getProperty("user.dir"); public static final String FILE_ROOT = "D:\\"; public static void main(String[] args) { JxdHttpConnector connector = new JxdHttpConnector(); connector.start(); } }
到了这里,关于手写一个民用Tomcat (03)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!