`
xiaoZ5919
  • 浏览: 400268 次
  • 性别: Icon_minigender_1
  • 来自: 安平人@北京
博客专栏
Group-logo
Netty学习笔记
浏览量:72748
社区版块
存档分类
最新评论

Nio框架需要注意的两个问题(2)

阅读更多

    书接上回,上次说到了selector的register和select会有锁冲突,这次再来考虑write的问题。

1. channel.write(Bytebuffer)是不是总是可写,当socket的writeBuffer满的时候会返回0,说明不能再写进任何字节。假设要写入一个很大的ByteBuffer,有可能需要分多次写。

2. channel上执行write操作需要获得锁保证同步,如果用户在应用代码中多处同时执行则会有锁竞争。

     我们知道NIO是无阻塞同步的IO,无阻塞说的是读或者写的就绪状态。一般来说写的流程是这样的,使channel对write感兴趣,然后轮询selector的select方法,遍历selectionKey,如果可写则对给channel执行写操作

 

 while (true) {

                try {
                    handlerRegister();
                    keyCount = selector.select(selectTimeout);
                    if(keyCount > 0)
                        debug(Thread.currentThread().getName() + " selected:" + keyCount);
                    Iterator<SelectionKey> iterator =
                            keyCount > 0 ? selector.selectedKeys().iterator() : null;
                        // Walk through the collection of ready keys and dispatch
                        // any active event.
                        while (iterator != null && iterator.hasNext()) {
                            SelectionKey sk = iterator.next();
                            NioSession session = (NioSession)sk.attachment();
                            // Attachment may be null if another thread has called
                            // cancelledKey()
                            if (session == null) {
                                iterator.remove();
                            } else {
                                iterator.remove();
                                if(sk.isValid() && sk.isWritable()){
                                    debug("Session write:" + session);
                                    session.write();//可写时 执行写操作
                                }else if(sk.isValid() && sk.isReadable()){
                                    debug("Session read:" + session);
                                    session.read();
                                }else{
                                	debug("Session close from select");
                                    session.close();
                                }
                            }
                        }//while
                } catch (IOException e) {
                   debug("I'm here");
                    e.printStackTrace();
                }
            }

        }

 从上面的代码我们很快就发现一个问题,这个写操作是在Poller的SelectorLoop,假设我们需要在程序代码中执行write操作的时候,根本不知道什么时候可写。那我们不管什么selector的可读可写。直接执行channel.write()是否可以。可以不总是可行,就像前面提到的。writeBuffer已满是不能写入任何byte的。

     对于这个问题,Tomcat和Netty采用不同的解决方案,先说一个tomcat的方案:

     Tomcat采用阻塞写的方案,首先循环执行channle.write(buffer)直到不可写,当buffer没有写完即hasRemaining为true,则注册到一个blockingSelector执行不断轮询阻塞写。一般来说tomcat返回的html没有那么大就不需要注册给阻塞的selector,tomcat这样处理而只在Poller中执行读操作,还有另外一个好处。减少了每个SelectorLoop的时间把所有的时间都交给了读事件的处理大大提交了吞吐量。

 

 try {
            while ( (!timedout) && buf.hasRemaining()) {
                if (keycount > 0) { //only write if we were registered for a write
                    int cnt = socket.write(buf); //write the data
                    if (lastWrite != null) lastWrite.set(cnt);
                    if (cnt == -1)
                        throw new EOFException();
                    written += cnt;
                    if (cnt > 0) {
                        time = System.currentTimeMillis(); //reset our timeout timer 首先直接执行channel的write直到不能写入任何byte,这时候就需要交给另外一个selector处理
                        continue; //we successfully wrote, try again without a selector
                    }
                }
                try {
                    if ( att.getWriteLatch()==null || att.getWriteLatch().getCount()==0) att.startWriteLatch(1);
                    poller.add(att,SelectionKey.OP_WRITE,reference);//注册给阻塞的selector
//同时加了一个CountDownLatch,如果Selector的select一直没有检测到该channel可写而执行countDown()则会后续根据count是否超时                    att.awaitWriteLatch(writeTimeout,TimeUnit.MILLISECONDS);
                }catch (InterruptedException ignore) {
                    Thread.interrupted();
                }
                if ( att.getWriteLatch()!=null && att.getWriteLatch().getCount()> 0) {
                    //we got interrupted, but we haven't received notification from the poller.
                    keycount = 0;
                }else {
                    //latch countdown has happened
                    keycount = 1;
                    att.resetWriteLatch();
                }

                if (writeTimeout > 0 && (keycount == 0))
                    timedout = (System.currentTimeMillis() - time) >= writeTimeout;
            } //while
            if (timedout)
                throw new SocketTimeoutException();
        } finally {
            poller.remove(att,SelectionKey.OP_WRITE);
            if (timedout && reference.key!=null) {
                poller.cancelKey(reference.key);
            }
            reference.key = null;
        }

  blog编辑器有点不太好用,后续再介绍一个Netty的解决方案。

0
0
分享到:
评论

相关推荐

    常见NIO开源框架(MINA、xSocket)学习

    不过实际应用中一个socket服务器采用传统的阻塞式socket方式通信可能会是一场灾难,一路socket同时进行读写操作可能就需要两条线程,如果需要并发一百路socket(这个量其实很小了),可能就是两百条线程,大概几分钟...

    MINA通讯框架的两个简单实例和文档

    Apache的Mina(Multipurpose Infrastructure Networked ... NIO框架  客户端/服务端框架(典型的C/S架构)  网络套接字(networking socket)类库  事件驱动的异步API(注意:在JDK7中也新增了异步API)

    Apache Mina Server 2.0 参考手册

    Mina 主要有1.x 和2.x 两个分支,这里我们讲解最新版本2.0,如果你使用的是Mina 1.x, 那么可能会有一些功能并不适用。学习本文档,需要你已掌握JAVA IO、JAVA NIO、JAVA Socket、JAVA 线程及并发库(java.util....

    Dubbo面试28题答案详解:核心功能+服务治理+架构设计等

    RPC 指的是远程调用协议,也就是说两个服务器交互数据。 2.Dubbo的由来? 互联网的快速发展,Web应用程序的规模不断扩大,一般会经历如下四个发展阶段。 Dubbo的主要应用场景? 透明化的远程方法调用,就像调用本地...

    Apache-Mina-Server-2.0中文参考手册V1.0.docx

    Mina 主要有 1.x 和 2.x 两个分支,这里我们讲解最新版本 2.0,如果你使用的是 Mina 1.x,那么可能会有一些功能并不适用。学习本文档,需要你已掌握 JAVA IO、JAVA NIO、JAVA Socket、JAVA 线程及并发库(java.util....

    mina中文开发手册.pdf

    Apache Mina Server 是一个网络通信应用框架,也就是说,它主要是对基于TCP/IP、UDP/IP 协议栈的通信框架(当然,也可以提供JAVA 对象的序列化服务、虚拟机管道通信服务等),...Mina 主要有1.x 和2.x 两个分支…………

    服务端各类面试题合集.pdf

    另外由于依托了Spirng、SpirngBoot的优势之上,两个框架在开始目标就不一致 Dubbo定位服务治理、SpirngCloud是一个生态 1.2 Dubbo支持哪些序列化方式? 默认使用Hessian序列化,还有Duddo、FastJson、Java自带序列化...

    Java高并发实战_java高并发_高并发_

    介绍了两个重要的并行性能评估定律, 以及 Java 内存模型 JMM。第2章介绍了 Java 并行程序开发的基础, 包括 Java 中 Thread 的基本使用方法等第3章介绍了 JDK 内部对并行程序开发的支持, 主要介绍 JUC (Java.util....

    JDK_API_1_6_zh_CN_downcc.com.zip 良心一级分

    java.awt.dnd Drag 和 Drop 是一种直接操作动作,在许多图形用户界面系统中都会遇到它,它提供了一种机制,能够在两个与 GUI 中显示元素逻辑相关的实体之间传输信息。 java.awt.event 提供处理由 AWT 组件所激发的...

    java开源包2

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    Rabbit:RPC框架,使用ZooKeeper,Netty,期待良好的设计

    2、RPC与HTTP请求的区别:利用应用层的HTTP协议,也可以满足客户/服务器模式的信息交换,那为何还需要更为复杂的RPC框架呢?我们知道,使用HTTP接口,一般有四个过程:(3次握手)建立(TCP协议)连接,发送请求信息...

    编程狂人第十二期

    Java IO vs NIO vs AIO vs 协议Servlet 3.0 以及NIO的框架 Integer.valueOf(String) 方法之惑 在运行期通过反射了解JVM内部机制 程序设计 Objective-C相关Category的收集 文章: 豆瓣 CODE 两年历程回顾:git 不是...

    java开源包1

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包11

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包3

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包6

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包5

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包10

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包4

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包8

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

Global site tag (gtag.js) - Google Analytics