<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>-Flyぁ梦- &#187; 异步IO</title>
	<atom:link href="http://blog.11034.org/tag/%e5%bc%82%e6%ad%a5io/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.11034.org</link>
	<description></description>
	<lastBuildDate>Sun, 22 Jun 2025 08:59:05 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.2.38</generator>
	<item>
		<title>Tomcat的Connector：Coyote</title>
		<link>http://blog.11034.org/2013-05/coyote.html</link>
		<comments>http://blog.11034.org/2013-05/coyote.html#comments</comments>
		<pubDate>Mon, 20 May 2013 14:01:09 +0000</pubDate>
		<dc:creator><![CDATA[-Flyぁ梦-]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[coyote]]></category>
		<category><![CDATA[Socket]]></category>
		<category><![CDATA[Tomcat]]></category>
		<category><![CDATA[多线程]]></category>
		<category><![CDATA[异步IO]]></category>
		<category><![CDATA[线程池]]></category>

		<guid isPermaLink="false">http://blog.stariy.org/?p=1808</guid>
		<description><![CDATA[上一篇博文讲了Tomcat的系统架构，今天花了一天时间研究了下coyote的源码，大致对普通IO版本有所了解。 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>上一篇博文讲了<a title="Tomcat6源码学习" href="/2013-05/tomcat6.html" target="_blank">Tomcat的系统架构</a>，今天花了一天时间研究了下coyote的源码，大致对普通IO版本有所了解。被同学提醒后发现，Tomcat6已经支持异步IO了，但默认是普通IO版本，需要在Connector的protocol参数中定义为Http11NioProtocol才开启异步IO模式。</p>
<p>主要的代码，Socket的服务在org.apache.tomcat.util.net.JIoEndpoint类，解析处理HTTP请求在org.apache.coyote.http11包的Http11Protocol类和Http11Processor类，org.apache.catalina.connector.CoyoteAdapter负责连接Connector模块（coyote）和Container模块。</p>
<p>线程池默认用的JIoEndpoint类中的子类WorkerStack，若在server.xml配置使用了Executor，则使用org.apache.catalina.core.StandardThreadExecutor（对ThreadPoolExecutor的一层包装）。并发量高的情况下Executor的效率会高一些。<span id="more-1808"></span></p>
<h2>Coyote普通IO流程</h2>
<p>在Catalina主线程启动过程中：</p>
<p>StandardService的init()中，在JIoEndpoint.init()中，ServerSocket(port = 8080, backlog = 100)被new出来。</p>
<p>StandardService的start()中，在JIoEndpoint.start()中，一个新的线程（名叫http-8080-Acceptor-0）被start()，这个由JIoEndpoint.Accept内部类执行run()的线程干的活就是不停地从serverSocket.accept()，然后根据线程池的选择拿一个线程去处理socket。因为处理在新的线程，Acceptor线程继续等待accept()。</p>
<p>若使用默认的WorkerStack线程池，JioEndpoint.getWorkerThread().assign(socket);使Worker线程获得socket实例后，就可以在新线程中处理socket。</p>
<p>若使用Executor线程池，则new出一个JioEndpoint.SocketProcessor()交给Executor.execute()，在新线程中处理socket。</p>
<p>不管哪种线程池方法，新线程中使用一样的代码，调用Http11Protocol$Http11ConnectionHandler.process(socket)，这里使用了一个ConcurrentLinkedQueue用来保存Http11Processor实例，拿一个进行处理。</p>
<p>Http11Protocol.process()具体解析HTTP请求。解析过程中，将参数塞进request和response，再调用CoyoteAdapter.service(request, response)，这样就进入Container模块去调用Servlet代码。</p>
<p>结束后，回收Http11Processor实例，回收线程。</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;流程结束分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>好像代码也没有太难看不懂，大多数复杂的线程同步操作都由java.util.concurrnt包里的类实现了。</p>
<h2>Worker线程的assign()和await()</h2>
<p>Acceptor线程调用Worker.assign( socket )，将socket对象赋给Worker线程，然后Worker线程中的await()方法通过线程同步，Worker线程被唤醒并拿到了socket就可以在自己线程里顺利执行了。</p>
<p>这块线程同步的代码蛮有意思的，而且Worker线程也借助这边的wait()和notifyall()实现挂起和唤醒。</p>
<h2>server.xml参数调优</h2>
<p><strong>开启异步IO</strong></p>
<p>Connector的配置中，将protocol=“HTTP/1.1”改为“org.apache.coyote.http11.Http11NioProtocol”就可以使用nio包的异步IO，效率高不少。</p>
<p>对java.nio包特别是异步IO这一块了解甚浅，而且Tomcat对这一块的实现略复杂，看懂略有难度，努力！</p>
<p>同样地方还能改为“org.apache.coyote.http11.Http11AprProtocol”，据说利用底层OS的异步IO，需要APR和Native这其他两个组件的支持才能工作，效率更高，不是太确定。</p>
<p><strong>开启Executor并在Connector中使用</strong></p>
<p>Executor的2个配置参数，minSpareThreads和maxThreads，对应到ThreadPoolExecutor(int <strong>corePoolSize</strong>,  int <strong>maximumPoolSize</strong>, &#8230;)这个构造的前面2个参数。分别表示活跃线程数和最大线程数。</p>
<p><strong>Connector的参数：</strong></p>
<ul>
<li>maxThreads，对应JIoEndpoint类中的maxThreads变量，默认为200。若有Executor加入则maxThreads被取代。</li>
<li>acceptCount，对应JIoEndpoint类中的backlog变量，默认为100，用作ServerSocket的第二个参数。ServerSocket里等待队列的长度。</li>
</ul>
<h4  class="related_post_title">看看 coyote , Socket , Tomcat , 多线程 , 异步IO , 线程池</h4><ul class="related_post"><li>2013-05-19 -- <a target="_blank" href="http://blog.11034.org/2013-05/tomcat6.html" title="Tomcat6源码学习">Tomcat6源码学习</a></li><li>2016-06-08 -- <a target="_blank" href="http://blog.11034.org/2016-06/tomcat_shutdown.html" title="Tomcat监听shutdown释放数据库连接池">Tomcat监听shutdown释放数据库连接池</a></li><li>2016-06-06 -- <a target="_blank" href="http://blog.11034.org/2016-06/tomcat_https.html" title="Tomcat启用https服务">Tomcat启用https服务</a></li><li>2016-03-17 -- <a target="_blank" href="http://blog.11034.org/2016-03/java_client_socket_exceptions.html" title="Java客户端Socket在服务端重启后的异常情况处理">Java客户端Socket在服务端重启后的异常情况处理</a></li><li>2016-03-01 -- <a target="_blank" href="http://blog.11034.org/2016-03/simpledateformat_thread_not_safe.html" title="jdk中SimpleDateFormat的实例线程不安全">jdk中SimpleDateFormat的实例线程不安全</a></li></ul><h4 class="related_post_title">看看 Java </h4><ul class="related_post"><li>2016-09-09 -- <a target="_blank" href="http://blog.11034.org/2016-09/64bits_linux_arena_memory.html" title="64位Linux下Java进程堆外内存迷之64M问题">64位Linux下Java进程堆外内存迷之64M问题</a></li><li>2016-08-18 -- <a target="_blank" href="http://blog.11034.org/2016-08/java_concurrency_in_practice.html" title="读java concurrency in practice">读java concurrency in practice</a></li><li>2016-08-05 -- <a target="_blank" href="http://blog.11034.org/2016-08/thread_stop.html" title="线程清理">线程清理</a></li><li>2016-06-21 -- <a target="_blank" href="http://blog.11034.org/2016-06/futuretask.html" title="FutureTask简单分析和用法">FutureTask简单分析和用法</a></li><li>2016-06-21 -- <a target="_blank" href="http://blog.11034.org/2016-06/semaphore.html" title="Semaphore简单分析">Semaphore简单分析</a></li>]]></content:encoded>
			<wfw:commentRss>http://blog.11034.org/2013-05/coyote.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Java学习之IO与NIO篇</title>
		<link>http://blog.11034.org/2010-08/java_io_nio.html</link>
		<comments>http://blog.11034.org/2010-08/java_io_nio.html#comments</comments>
		<pubDate>Wed, 04 Aug 2010 17:12:35 +0000</pubDate>
		<dc:creator><![CDATA[-Flyぁ梦-]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Buffer]]></category>
		<category><![CDATA[io]]></category>
		<category><![CDATA[异步IO]]></category>

		<guid isPermaLink="false">http://blog.stariy.info/?p=147</guid>
		<description><![CDATA[Java的IO相较于其他语言，感觉是比较抽象和复杂的，当然等你理解了它并且熟练了，它的强大性就马上体现出来了。 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Java的IO相较于其他语言，感觉是比较抽象和复杂的，当然等你理解了它并且熟练了，它的强大性就马上体现出来了。其实本来只是想写nio的，把io也顺带理一下吧。</p>
<p>Java的io最重要的一个概念就是流，就像一个水管插在文件和终端之间，每个字节都是一滴水，按顺序单方向地流动，这样理解不知道是不是容易些？流主要分以下几种类型：<br />
<span id="more-147"></span></p>
<ul>
<li>输入流和输出流：就是流的方向。 InputStream和Reader是输入，OutputStream和Writer是输出，很简单</li>
<li>字节流和字符流：流的最小单位，字节流好理解，字符流是因为gbk和Unicode等的存在，单独一个字节是无法表示一个字符的，2个字节为单位读取。InputStream和OutputStream是字节流，Reader和Writer是字符流</li>
<li>基础流和封装流：以上四种都是基础流，提供的API基本都是get()一个字节/字符，write()一个字节/字符；封装流将基础流包装了一下，提供了更多的功能，比如最常用的BufferedStream，用来缓存流从而提高IO效率；DataStream，提供读写Java基本类型的流，可以直接写入一个int、double、UTFString等；StreamReader、StreamWriter，将字节流转换为字符流；其他还有ByteArrayStream、FileStream等，字面意思就很明白了</li>
</ul>
<p>弄清楚这些，其实Java IO基本就能搞明白了。传说中的三层流封装就很明了了，第一层基础流，比如InputSream，第二层InputStreamReader，转换为字符流，第三层再包装一个BufferedReader，提高IO效率，很清楚也很简单，不要被这个流程搞晕了。大致上基础io包也就这些东西了。</p>
<p>接下来就讲讲刚看的nio包，nio比基础io更抽象更难用，其实基础io功能也很强大了，所以一直没鼓起勇气去学nio。在百度文库下到一个不错的教程，2天就看完了，讲讲自己的心得。</p>
<p>先说nio中比较易用且实用的，就是各种Buffer，最基础的ByteBuffer，CharBuffer也不错，还有各种其他类型的Buffer。Buffer有position、limit、capacity属性。position为当前buffer操作到了哪个位置，包括读和写，limit为用户可自己限制的此buffer的结尾位置，capacity就是buffer的大小，综合起来就是：0 &lt;=position &lt;= limit &lt;= capacity &lt;= size of array。主要的API有flip()，主要用于将数据读入到buffer后，将limit设为当前的position，然后将position设为0，就可以从头到尾把所有的数据读出来了。</p>
<p>再说说文件读写中的FileChannel，这个是一个nio中新的概念，类似于stream，可以从FileStream中通过getChannel()获取，然后FileChannel的read(ByteBuffer)方法直接将字节流读入buffer，操作挺方便；官方介绍FileChannel说这是个可读可写并且双向的流，可读可写倒确实，不过双向我暂时没有看出来，文件copy的过程中还是需要建立1个InputStream获得一个FileChannel，1个OutputStream获得一个FileChannel，不能用1个FileChannel来搞定，双向意义何在？</p>
<p>综合FileChannel和Buffer举个例子：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre class="java" style="font-family:monospace;"><span style="color: #003399;">FileInputStream</span> fis <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">FileInputStream</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">File</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;a.txt&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
FileChannel fin <span style="color: #339933;">=</span> fis.<span style="color: #006633;">getChannel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003399;">FileOutputStream</span> fos <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">FileOutputStream</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">File</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;b.txt&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
FileChannel fout <span style="color: #339933;">=</span> fos.<span style="color: #006633;">getChannel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
ByteBuffer buffer <span style="color: #339933;">=</span> ByteBuffer.<span style="color: #006633;">allocate</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1024</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//1024字节的buffer</span>
<span style="color: #000000; font-weight: bold;">while</span><span style="color: #009900;">&#40;</span>fin.<span style="color: #006633;">read</span><span style="color: #009900;">&#40;</span>buffer<span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
     buffer.<span style="color: #006633;">flip</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//buffer写满，position重新置0，limit置为结尾，方便使用</span>
     fout.<span style="color: #006633;">write</span><span style="color: #009900;">&#40;</span>buffer<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
     buffer.<span style="color: #006633;">clear</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//清空buffer</span>
<span style="color: #009900;">&#125;</span>
fin.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
fout.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
fis.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
fos.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>还有一个也比较实用的是Charset和对应的CharsetEncoder和CharsetDecoder，可以将字节流与不同的字符流之间相互转换。</p>
<p>最后是nio中最麻烦应该也是最强大的地方，异步IO，这儿涉及很多新的概念和类，Selector、ServerSocketChannel、SelectionKey，注册事件、监听事件、处理事件等，我就看了一个下午左右，理解也不是非常深，大致知道这些类怎么串起来用。还是看程序来的学得快，程序我放到附件中，理解了NIOServer和NIOClient，就有了基础了。当然程序中比较缺乏的一点就是处理事件的时候是单线程的，这样事件队列一旦越积越多，速度就慢了，开几个线程同时来响应事件是比较好的方案。</p>
<p>nio中还有其他的一些东西，比如Buffer的一些深入 direct Buffer，越过临时buffer提高速度；Memory-mapped file I/O，提高文件读写速度；File locking（这个还不是很懂）。</p>
<p>又掌握了Java中一个很重要的类包，还是挺开心的，坚持写完这篇日志也是受了gstar博客大牛的影响，多写写技术blog哈~接下来的目标，当然是把nio好好再消化下，然后自我觉得没有掌握而觉得很重要的还有java.util.concurrency包、java.security包、java.rmi包，主要这些平时比较少用，嗯，慢慢来~</p>
<p>附：包括一个NIO的异步IO的2个示范类，随意看看</p>
<p><a href="/wp-content/uploads/2010/08/NIO.zip" rel="attachment">NIO异步IO示范</a></p>
<h4  class="related_post_title">看看 Buffer , io , 异步IO</h4><ul class="related_post"><li>2013-05-20 -- <a target="_blank" href="http://blog.11034.org/2013-05/coyote.html" title="Tomcat的Connector：Coyote">Tomcat的Connector：Coyote</a></li></ul><h4 class="related_post_title">看看 Java </h4><ul class="related_post"><li>2016-09-09 -- <a target="_blank" href="http://blog.11034.org/2016-09/64bits_linux_arena_memory.html" title="64位Linux下Java进程堆外内存迷之64M问题">64位Linux下Java进程堆外内存迷之64M问题</a></li><li>2016-08-18 -- <a target="_blank" href="http://blog.11034.org/2016-08/java_concurrency_in_practice.html" title="读java concurrency in practice">读java concurrency in practice</a></li><li>2016-08-05 -- <a target="_blank" href="http://blog.11034.org/2016-08/thread_stop.html" title="线程清理">线程清理</a></li><li>2016-06-21 -- <a target="_blank" href="http://blog.11034.org/2016-06/futuretask.html" title="FutureTask简单分析和用法">FutureTask简单分析和用法</a></li><li>2016-06-21 -- <a target="_blank" href="http://blog.11034.org/2016-06/semaphore.html" title="Semaphore简单分析">Semaphore简单分析</a></li>]]></content:encoded>
			<wfw:commentRss>http://blog.11034.org/2010-08/java_io_nio.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
