伪异步IO理解
伪异步IO实在堵塞IO的基础上将每个client发送过来的请求由新创建的线程来处理改进为用线程池来处理。因此避免了为每个client请求创建一个新线程造成的资源耗尽问题。
来看一下伪异步IO的服务端代码:
线程池类
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; /**
* @author zhouxuejun
*
* @date 2014年10月21日 上午10:05:43
*/
public class TimerServerHandlerExecutePool {
private ExecutorService executor; public TimerServerHandlerExecutePool(int maxPoolSize, int queueSize) {
executor = new ThreadPoolExecutor(Runtime.getRuntime()
.availableProcessors(), maxPoolSize, 120L, TimeUnit.SECONDS,
new ArrayBlockingQueue<java.lang.Runnable>(queueSize));
} public void execute(java.lang.Runnable task) {
executor.execute(task);
}
}
堵塞IO服务端代码:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket; import com.bio.demo.Server.handler.TimerServerHandler;
import com.bio.demo.threadPool.TimerServerHandlerExecutePool; /**
* @author zhouxuejun
*
* @date 2014年10月20日 下午7:08:58
*/
public class TimeServer { public static ServerSocket server=null;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
server=new ServerSocket(8080);
Socket socket=null;
TimerServerHandlerExecutePool singleExecutor=new TimerServerHandlerExecutePool(50, 10000);
while(true){
socket=server.accept();
//new Thread(new TimerServerHandler(socket)).start();
singleExecutor.execute(new TimerServerHandler(socket));//用线程池的方式来处理client请求
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } }
从表面上来看,因为线程池和消息队列都是有界的,因此。不管client并发连接数多大。他都不会导致线程个数过于膨胀或者内存溢出。相比传统的一连接一线程模型,是一种非常好的改进。可是因为底层的通信依旧採用同步堵塞模型。因此无法从根本上解决这个问题。
以下让我们来深入堵塞IO底层来分析,首先我们来看看java同步IO的API说明:
先来看看Java输入流,以下是InputStream类中截取的一部分代码
/**
* Reads some number of bytes from the input stream and stores them into
* the buffer array <code>b</code>. The number of bytes actually read is
* returned as an integer. <span style="color:#FF0000;"><strong>This method blocks until input data is</strong></span>
* <span style="color:#FF0000;"><strong>available, end of file is detected, or an exception is thrown.</strong></span>
*
* <p> If the length of <code>b</code> is zero, then no bytes are read and
* <code>0</code> is returned; otherwise, there is an attempt to read at
* least one byte. If no byte is available because the stream is at the
* end of the file, the value <code>-1</code> is returned; otherwise, at
* least one byte is read and stored into <code>b</code>.
*
* <p> The first byte read is stored into element <code>b[0]</code>, the
* next one into <code>b[1]</code>, and so on. The number of bytes read is,
* at most, equal to the length of <code>b</code>. Let <i>k</i> be the
* number of bytes actually read; these bytes will be stored in elements
* <code>b[0]</code> through <code>b[</code><i>k</i><code>-1]</code>,
* leaving elements <code>b[</code><i>k</i><code>]</code> through
* <code>b[b.length-1]</code> unaffected.
*
* <p> The <code>read(b)</code> method for class <code>InputStream</code>
* has the same effect as: <pre><code> read(b, 0, b.length) </code></pre>
*
* @param b the buffer into which the data is read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception IOException If the first byte cannot be read for any reason
* other than the end of the file, if the input stream has been closed, or
* if some other I/O error occurs.
* @exception NullPointerException if <code>b</code> is <code>null</code>.
* @see java.io.InputStream#read(byte[], int, int)
*/
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
红色加粗部分的AIP说明,当对Socket的输入流进行读取操作的时候。它会一直堵塞下去,知道三件事情发生:
1)有数据可读
2)可用数据读取完成
3)发生空指针或者IO异常
这意味着当对方发送请求或者应答消息比較缓慢、或者网络传输教慢时,读取输入流一方的同学线程将被长时间堵塞。
以下我再从输出流进行分析,来看看输出流OutputStream类,以下是截取的部分代码:
/**
* <span style="color:#FF0000;"><strong>Writes <code>len</code> bytes from the specified byte array</strong></span>
* <span style="color:#FF0000;"><strong>starting at offset <code>off</code> to this output stream.</strong></span>
* The general contract for <code>write(b, off, len)</code> is that
* some of the bytes in the array <code>b</code> are written to the
* output stream in order; element <code>b[off]</code> is the first
* byte written and <code>b[off+len-1]</code> is the last byte written
* by this operation.
* <p>
* The <code>write</code> method of <code>OutputStream</code> calls
* the write method of one argument on each of the bytes to be
* written out. Subclasses are encouraged to override this method and
* provide a more efficient implementation.
* <p>
* If <code>b</code> is <code>null</code>, a
* <code>NullPointerException</code> is thrown.
* <p>
* If <code>off</code> is negative, or <code>len</code> is negative, or
* <code>off+len</code> is greater than the length of the array
* <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
* @exception IOException if an I/O error occurs. In particular,
* an <code>IOException</code> is thrown if the output
* stream is closed.
*/
public void write(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
}
红色加粗的API说明,当调用OutputStream的write方法写输出流的时候,它将会被堵塞。知道所有要发送的字节所有写入完成,或者发生异常。
通过对堵塞IOAPI输入,输出文档的分析。我们了解到堵塞IO的读和写都是同步堵塞的,堵塞的时间取决于对方IO线程的处理速度和IO的传输速度。可是我们无法保证生产环境的网络状况和对端的应用程序能足够快,一个稳定可靠性高的应用不能依赖对方的处理速度。
所以才有了NIO的出现。
伪异步IO理解的更多相关文章
- netty权威指南学习笔记一——NIO入门(2)伪异步IO
在上一节我们介绍了四种IO相关编程的各个特点,并通过代码进行复习了传统的网络编程代码,伪异步主要是引用了线程池,对BIO中服务端进行了相应的改造优化,线程池的引入,使得我们在应对大量客户端请求的时候不 ...
- 伪异步IO
针对传统的BIO编程,当客户端数量一直增加的情况下,可能会导致服务器直接奔溃掉,进而出现了一种伪异步IO的线程方式. 先看一下代码: 看一下server端的代码: 其中使用了自定义的一个线程池Hand ...
- Java IO编程全解(三)——伪异步IO编程
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7723174.html 前面讲到:Java IO编程全解(二)--传统的BIO编程 为了解决同步阻塞I/O面临 ...
- JDK 伪异步编程(线程池)
伪异步IO编程 BIO主要的问题在于每当有一个新的客户端请求接入时,服务端必须创建一个新的线程处理新接入的客户端链路,一个线程只能处理一个客户端连接.在高性能服务器应用领域,往往需要面向成千上万个客户 ...
- 【译】深入理解python3.4中Asyncio库与Node.js的异步IO机制
转载自http://xidui.github.io/2015/10/29/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3python3-4-Asyncio%E5%BA%93% ...
- node中异步IO的理解
解释性语言和编译型语言的区别: 计算器不能直接的理解高级语言,只能理解机器语言,所以必须把高级语言翻译为机器语言,翻译的方式有两种,一个是编译,一个是解释. 解释性语言的程序不需要编译,它是在运行程序 ...
- 深入理解非阻塞同步IO和非阻塞异步IO
这两篇文章分析了Linux下的5种IO模型 http://blog.csdn.net/historyasamirror/article/details/5778378 http://blog.csdn ...
- 小白对异步IO的理解
前言 看到越来越多的大佬都在使用python的异步IO,协程等概念来实现高效的IO处理过程,可是我对这些概念还不太懂,就学习了一下. 因为是初学者,在理解上有很多不到位的地方,如果有错误,还希望能够有 ...
- python IO模式(多路复用和异步IO深入理解)
1.事件渠道模型.事件渠道为异步IO的原型. 2.IO模式,一次IO调用会经历两个阶段.一.等待数据阶段,将数据从网络或者是磁盘读取到系统内核(kennel) 二.将数据从内核拷贝到进程中. 基于这两 ...
随机推荐
- PowerDesigner中SQL文件、数据库表反向生成PDM
1 反向生成PDM 1) 创建一个空的PDM模型(选择相应的DBMS): 2) 选择[Database]--[Update Model from Database ...
- 秒杀多线程第二篇 多线程第一次亲热接触 CreateThread与_beginthreadex本质差别
本文将带领你与多线程作第一次亲热接触,并深入分析CreateThread与_beginthreadex的本质差别,相信阅读本文后你能轻松的使用多线程并能流畅准确的回答CreateThread与_beg ...
- linux LNMP自动安装脚本
#!/bin/bashsoft_dir="/home/soft"config_dir="/home/config"httpd="httpd-2.0.5 ...
- Windows Server时间服务器配置方法
1 时间服务器经常会碰到客户端机器需要和服务器在时间上保持同步,否则会出现各种问题,特别是有时间相关的触发功能的时候. 为解决各设备间时间统一的问题,我们可在网络中设置一台服务器使其作为基准时间,其它 ...
- 恩布企业 IM 安卓端 1.3,服务端 1.12 公布
恩布企业IM的 Android 安卓开源手机client EntboostIM 公布 1.3 版本号.同一时候恩布IM服务端更新至 1.12 版本号; 安卓端主要更新内容: 添加收发手机文件功能: 登 ...
- [置顶] Guava学习之Multimap
相信大家对Java中的Map类及其之类有大致的了解,Map类是以键值对的形式来存储元素(Key->Value),但是熟悉Map的人都知道,Map中存储的Key是唯一的.什么意思呢?就是假如我们有 ...
- Java重写方法与初始化的隐患(转)
原文出处: Shawon 虽然文章标题是Java, 但几乎所有面向对象设计的语言都遵守这个初始化流程, 感谢廖祜秋liaohuqiu_秋百万指出, 之前忘记提这个了. 前言 drakeet写了个和Re ...
- TestThreadPoolExecutor.java
package ; import java.io.IOException;import java.io.InputStream;import java.util.List;impo ...
- Microsoft Build 2016
Microsoft Build 2016 Day 1 记录 去年今日:Microsoft Build 2015 汇总 今年的 Bulid 时间是 3.30-4.1,第一天的主角主要是 Window ...
- Hibernate主键生成策略简单总结
数据库表主键的知识点: Generator 为每个 POJO 的实例提供唯一标识. 一般情况,我们使用"native".class 表示采用由生成器接口net.sf.hiberna ...