tomcat启动后,有两个(两类)线程在工作,Acceptor和PollerClient,分别在idea中frams栈帧中可以debug看到。主要功能在这篇文章中有简单介绍。
原文链接:https://blog.youkuaiyun.com/u011385186/article/details/53148702
这里主要记录两个问题,
1.Acceptor和Poller作为runnable,他们的start()是如何开启的?
tomcat启动过程主要是catlina,coyote,processor,endpoint等组件的链式调用,先init链式调用一遍,再start和startInternal链式调用一遍
acceptor线程的start:NioEndPoint的startInternal()方法中的startAcceptorThreads()方法调用
poller线程的start:NioEndPoint的startInternal()方法中调用,其中poller的空参构造调用了selector.open(),即一个poller对应一个selector
2.tomcat启动后,二者run()方法运行中如何产生关联去处理请求的?
第1个问题说明了acceptor和PollerClient这俩线程是如何开启的,现在要记录这两个线程是如何工作的,也就是他们的run方法。
acceptor的run()方法:
1. socketChannel = serverSocketChannel.accept(); nio中的serverSocketChannel一直接收客户端请求,
2. setSocketOptions -> getPoller0().register(channel) -> addEvent® -> events.offer(event) -> queue[insert++] = t; serversocketchannel接收到客户端的channel后,取到一个poller线程,包装channel后注册channel,然后添加到poller的事件队列(同步队列SyncronizedQueue)events中
poller的run()方法():
- while true循环中, hasEvents = events();检查事件同步队列中events.poll()是否有事件,有就开始处理事件(此事件是由acceptor线程添加到队列当中的);
- .Iterator iterator =selector.selectedKeys().iterator()并遍历,处理所有事件 -> processKey() -> processSocket(READ/WRITE分别处理) -> Executor executor = getExecutor(); -> executor.execute(sc);调用线程池处理。
《这里的线程池,就是在tomcat配置文件server.xml中配置的线程池,如果对其命名,接下来debug会看到该名字的线程在处理请求》
主要核心应该是tomcat基于nio编程的NioEndPoint和NioChannel这两个类,更多地mark以后有机会再看。