首页 > 技术文章 > jetty分析

lkdirk 2017-04-23 17:47 原文

jetty处理过程:

1  new Server()

(1)初试化线程池  生成固定大小线程数,新来的线程放入BlockingQueue。

(2)初始化ServerConnector 

       初始化 scheduleExcotorScheduler 做一些线程调度,例如定期执行的线程等。

   初始化 byteBufferPool 一个buffer对象池,可以复用各buffer对象,减少gc,channel读取数据的时候可以复用。线程安全并且无锁,对象队列使用了concurrentLinkedQueue,性能提高明显。里面的对象不是等价的,因为可能不同线程需要不同太小的buffer,大小不一定。因此使用了延迟加载,buffer池在初始化的时候,需要指定buffer对象的范围,包括最小值,增量值,最大值;然后从最小容量到最大容量,建立一系列不同大小的bucket做代理,负责延迟加载;buffer池提供acquire()申请和release()释放,申请时需指定大小,从而定位到bucket(比如5.5k大小,会定位到6k的bucket),有则返回,没有则实例化,释放时,同样定位到bucket,清空buffer,放回queue中。如果申请的大小比范围还大,则有特殊处理,还是会new一个需要大小的buffer返回,只是释放的时候不会放入buffer池,让其自然被gc掉。

      维护connectionFactory ,用于创建连接对象,比如在aio/nio里面accept到一个连接的时候,把这个连接封装为对象。

      取得cpu数量,从而根据cpu数量决定使用多少acceptor线程数量,acceptor线程就是nio中用于accept的线程。总体数量不会太多。

      根据前面计算的结果实例化acceptor线程池。

      初始化ServerConnectorManager,管理nio的selector,计算selector的线程数量,经验值是min(4,可用cpu/2)。selector线程一般比acceptor线程多,因为accptor只处理一次,后续操作还需要多次使用selector,但是selector本身不处理具体逻辑,所以也不要太多。

  (3) 设置port 监听端口例如8080。

(4)关联server和connector  类似nio操作。

2 Server.start()

  (1)设置启动状态

  (2)启动过程

         1)注册shutDownMonitor,提供一些管理功能例如远程关闭等。

         2)获取线程池

         3)设置selector数量: 这个数量需要累计所有connector,因为可能存在多个connector。selector大于200就退出。

         4)维护bean,例如启动上面线程池;还有WebAppContext,定义一些servlet规范。

         5)启动connector: 创建并启动accepter线程和selector线程。

  (3)启动结束

3 http请求 

    (1)accept成功,channel设置为非阻塞模式,配置sokect。正式处理:选择可用的 ManageSelector线程(封装了select操作),后台会维护一个int,每次accept就++,然后取模selector数量,相当于轮询selector线程,做到平均分配,任务会提交到manager的线程安全队列changes中。

     (2)  ManagerSelector.run(),只要上面提到的selector线程队列中有任务,就开始执行,这一步关联了select和channel。然后进行正式的select(),得到并处理可用的selectkey。

推荐阅读