在前面的分析中介绍过,Acceptor的作用是控制与tomcat建立连接的数量,但Acceptor仅仅负责建立连接。socket内容的读写是通过Poller来实现的。
 
Poller使用java nio来实现连接的管理。

关于nio。主要须要明白三个概念:Channel、Selector和SelectionKey.
在这里的使用上。它们之间的关系能够简单这样理解,Channel必须注冊到Selector上才干用于接收socket数据。在Selector上有数据到达的Channel能够用SelectionKey来表示

[注冊]
Poller使用nio来进行socket数据的读写,一个通过Poller的register方法,注冊到Poller上。

对Poller的注冊。先进入Poller内部维护的一个事件队列上。

Poller线程在运行过程中会去检查队列,将channel注冊到selector上。为了保证在多线程同一时候訪问时数据的一致性,这个队

     列是一个SynchronizedQueue,使用synchronized来保证对队列中数据的一致性。
注冊的时候。每一个channel会有KeyAttachment对象,用来进行channel上的多线程并发运行时的控制。

ServerSocketChannel建立连接是在Acceptor上。

[队列]
队列定义例如以下 private final SynchronizedQueue<PollerEvent>
events = new SynchronizedQueue<>();

队列中的每一个元素是PollerEvent对象,它携带完毕的处理channel相关的信息。

每一个事件在处理过程中。会依据事件的状态。来实现Channel到Selector上的注冊。队列处理完毕后,每一个注冊到Poller上的channel就完毕了到Selector上的注冊。


[socket数据读取]
Poller线程的run方法的主题部分使用while(true)的无限循环来运行。当所属的Endpoint正常运行的时候,在每次运行过程中,处理其事件队列,调用selector来读取数据,然后处理读取到的数据。
在run方法中。会调用 events方法来处理事件队列
调用selector.selectNow或selector.select(xxx)来获取有数据到达的channel

[Poller缓存]
在Poller中使用的缓存是来其所属的Endpoint的缓存。keyCache和eventCache

eventCache是PollerEvent事件的缓存,在Poller上注冊的时候,从eventCache中取出PollerEvent对象。重置这个对象。然后再放入Poller的事件队列中。Poller在处理队列的过程中。每从队列中取出一个要处理的PollerEvent事件,处理完之后,把这个PollerEvent对象放回缓存中。
  ---- 避免频繁地创建PollerEvent对象和GC回收。


keyCache是相应的socket信息的缓存,在Poller上注冊的时候。从keyCache中取出KeyAttachment对象。重置这个对象,作用附件用于channel到selector上的注冊。在Processor处理完数据之后。将这个KeyAttachment对象放回keyCache中。  -----
避免频繁地创建KeyAttachment对象和GC回收。


[多线程并发控制]
events队列。为SychronizedQueue<PollerEvent>,SychronizedQueue提供的offer、poll、size和clear方法都使用了sychronizedkeyword进行修饰,用来保证同一时刻仅仅有一个线程能对队列进行读写。

系统中是同一时候有多个Poller线程在执行的。每一个Polle线程有各自的events队列。但每一个Poller线程可能同一时候被多个Acceptor线程调用进行注冊。


[属性说明]

Poller的属性例如以下


        private Selector selector;
        private final SynchronizedQueue<PollerEvent>
events =
                new SynchronizedQueue<>();

        private volatile boolean close
false;
        private long nextExpiration
= 0; //optimize expiration handling

        private AtomicLong
wakeupCounter = new AtomicLong(0);

        private volatile int keyCount
= 0;

selector,java nio必备组成部分
events 当前Poller的事件队列,主要是channel注冊事件
close 当前Poller是否可用的状态开关
nextExpiration 当前连接到此Poller上的socket超时的时限点。

Poller线程在其run方法的每遍运行过程中。会调用timeout方法来检查当前连接的socket,是否达到了超时的时限,假设达到了超时的时限。则告诉client连接超时。

每次运行完timeout方法后。会又一次设置nextExpiration的值

wakeupCounter的作用:1、告诉Poller当前有多少个新连接,这样当Poller进行selector的操作时,能够选择是否须要堵塞来等待读写请求到达。

2、标识Poller在进行select选择时。是否有连接到达。

假设有,就让当前的堵塞调用马上返回

这个地方比較隐晦,结合代码来进行解释

     channel注冊到Poller时运行的部分代码
       private void addEvent(PollerEvent
event) {
            events.offer(event);
            if (
wakeupCounter.incrementAndGet() == 0 ) selector.wakeup();
        }

     Poller的run方法部分代码

                if (wakeupCounter.getAndSet(-1)
> 0) {
              //if we are here, means we have other stuff to do
                    //do a non blocking select
                    keyCount = selector.selectNow();
                } else {
                    keyCount = selector.select(selectorTimeout);
                }
                wakeupCounter.set(0);

考虑以下的两个场景:
作用一。帮助Poller选择select方法
在run运行时,当前已经有了5个channel注冊到Poller上。所以wakeupCounter.getAndSet(-1) > 0 条件满足,Poller调用selector的非堵塞模式的select方法被调用
作用二,让当前堵塞的select方法马上返回
在run运行时,假设当前没有channel注冊到Poller上,wakeupCounter.getAndSet(-1) > 0 条件不满足。但wakeupCounter的值已经被设为-1了。Poller调用堵塞的select方法。在这期间,假设有新的channel注冊进来,则 wakeupCounter.incrementAndGet()
== 0条件满足。select.wakeup方法被调用。让selector.select(selectorTimeout)方法马上返回。
keyCount 注冊到Poller的channel中,I/O状态已经OK的的个数

tomcatserver解析(五)-- Poller的更多相关文章

  1. C语言文件操作解析(五)之EOF解析(转载)

      C语言文件操作解析(五)之EOF解析 在C语言中,有个符号大家都应该很熟悉,那就是EOF(End of File),即文件结束符.但是很多时候对这个理解并不是很清楚,导致在写代码的时候经常出错,特 ...

  2. Celery 源码解析五: 远程控制管理

    今天要聊的话题可能被大家关注得不过,但是对于 Celery 来说确实很有用的功能,曾经我在工作中遇到这类情况,就是我们将所有的任务都放在同一个队列里面,然后有一天突然某个同学的代码写得不对,导致大量的 ...

  3. dubbo源码解析五 --- 集群容错架构设计与原理分析

    欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 博客园 Dubbo 入门之二 --- 项目结构解析 博客园 Dubbo 源码分析系列之 ...

  4. Spring Security 解析(五) —— Spring Security Oauth2 开发

    Spring Security 解析(五) -- Spring Security Oauth2 开发   在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决 ...

  5. tomcatserver解析(六)-- Acceptor

    Acceptor负责用来管理连接到tomcatserver的数量,来看看Acceptor在tomcatserver中的应用,是怎样实现连接管理的,socket连接建立成功之后,是怎样实现内容的读写的( ...

  6. Java 面试知识点解析(五)——网络协议篇

    前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...

  7. AFNetworking (3.1.0) 源码解析 <五>

    这次主要开始讲解一下文件夹Serialization下的类AFURLRequestSerialization. AFURLRequestSerialization类遵守`AFURLRequestSer ...

  8. ReactiveCocoa源码解析(五) SignalProtocol的observe()、Map、Filter延展实现

    上篇博客我们对Signal的基本实现以及Signal的面向协议扩展进行了介绍, 详细内容请移步于<Signal中的静态属性静态方法以及面向协议扩展>.并且聊了Signal的所有的g功能扩展 ...

  9. ReactiveSwift源码解析(五) SignalProtocol的observe()、Map、Filter延展实现

    上篇博客我们对Signal的基本实现以及Signal的面向协议扩展进行了介绍, 详细内容请移步于<Signal中的静态属性静态方法以及面向协议扩展>.并且聊了Signal的所有的g功能扩展 ...

随机推荐

  1. php-fpm 记录慢执行日志

    有时候我们访问一个 php 的网站很慢,要想知道慢的原因,需要配置 php-fpm.conf,记录执行慢的日志: [root@localhost ~]$ cat /usr/local/php/etc/ ...

  2. Kafka版本升级 ( 0.10.0 -> 0.10.2 )

    升级Kafka集群的版本其实很简单,核心步骤只需要4步,但是我们需要在升级的过程中确保每一步操作都不会“打扰”到producer和consumer的正常运转.为此,笔者在本机搭了一个测试环境进行实际的 ...

  3. vue再次入手(数据传递②)

    接上篇~ 5.最后一种,互通:无所谓父组件或者是子组件,而是随时随地都能调用到数据的一种方法.便是利用vuex来管理数据,官网描述: Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它 ...

  4. PHP MYSQL 分表方法

    function get_hash_table($table,$uid){ $_str = crc32($uid); if($_str < 0 ){ $ret = "0".s ...

  5. ios设备唯一标识获取策略

    In iOS 7 and later, if you ask for the MAC address of an iOS device, the system returns the value 02 ...

  6. python中级---->pymongo存储json数据

    这里面我们介绍一下python中操作mangodb的第三方库pymongo的使用,以及简单的使用requests库作爬虫.人情冷暖正如花开花谢,不如将这种现象,想成一种必然的季节. pymongo的安 ...

  7. 使用 webpack 优化资源

    在前端应用的优化中,对加载资源的大小控制极其的重要,大多数时候我们能做的是在打包编译的过程对资源进行大小控制.拆分与复用.本片文章中主要是基于 webpack 打包,以 React.vue 等生态开发 ...

  8. jQuery事件处理(五)

    对原生js不熟悉看jQuery会困难很多.后续需要更多的关注下原生js jQuery封装之后的事件触发,其中一个分支(处理普通事件)是通过:elem.addEventListener( type, e ...

  9. Dumb Bones UVA - 10529[多米诺重构]

    Dumb Bones UVA - 10529   来自绿书p176  题意 你试图把一些多米诺骨牌排成直线,然后推倒它们.但是如果你在放骨牌的时候不小心把刚放的骨牌碰倒了,它就会把相临的一串骨牌全都碰 ...

  10. 【JSP】EL函数和自定义EL函数

    简介 EL原本是JSTL1.0中的技术(所以EL和JSTL感情如此好就是自然的了),但是从JSP2.0开始,EL就分离出来纳入了JSP的标准了.但是EL函数还是和JSTL技术绑定在一起.下面将介绍如何 ...