zoukankan      html  css  js  c++  java
  • tomcatserver解析(五)-- Poller

    在前面的分析中介绍过,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的的个数
  • 相关阅读:
    Python 函数 切片 迭代 列表生成器
    Python中各种集合 list tuple set dict
    Python学习 常识+基础基础
    《零基础学习Python》01
    原生API实现拖拽上传文件实践
    美团点评面试题小结(测试开发和前端开发)
    从实践的角度理解cookie的几个属性
    一道javascript面试题(闭包与函数柯里化)
    marked插件在线实时解析markdown的web小工具
    Github Page+Bmob实现简单动态功能
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/7401095.html
Copyright © 2011-2022 走看看