阻塞式和非阻塞式IO
有很多人把阻塞认为是同步,把非阻塞认为是异步;个人认为这样是不准确的,当然从思想上可以这样类比,但方式是完全不同的,下面说说在JAVA里面阻塞IO和非阻塞IO的区别
在JDK1.4中引入了一个NIO的类库,使得Java涉及IO的操作拥有阻塞式和非阻塞式两种,问一下阻塞IO与非阻塞IO有什么区别?有什么优缺点?
在阻塞模式下,若从网络流中读取不到指定大小的数据量,阻塞IO就在那里阻塞着。比如,已知后面会有10个字节的数据发过来,但是我现在只收到8个字节,那么当前线程就在那傻傻地等到下一个字节的到来,对,就在那等着,啥事也不做,直到把这10个字节读取完,这才将阻塞放开通行。
在非阻塞模式下,若从网络流中读取不到指定大小的数据量,非阻塞IO就立即通行。比如,已知后面会有10个字节的数据发过来,但是我现在只收到8个字节,那么当前线程就读取这8个字节的数据,读完后就立即返回,等另外两个字节再来的时候再去读取。
从上面可以看出,阻塞IO在性能方面是很低下的,如果要使用阻塞IO完成一个Web服务器的话,那么对于每一个请求都必须启用一个线程进行处理。而使用非阻塞IO的话,一到两个线程基本上就够了,因为线程不会产生阻塞,好比一下接收A请求的数据,另一下接收B请求的数据,等等,就是不停地东奔西跑,直接到把数据接收完了。
虽然说,非阻塞IO比阻塞IO有更高的性能,但是对于开发来的,难度就成数倍递增了。由于是有多少数据就读取多少数据,这样在读取完整之前需要将已经读取到的数据保存起来,而且需要与其他地方来的数据隔离开来不能混在一起,否则就不知道这数据是谁的了,呵呵。
我们都知道TCP是面向连接的传输层协议,一个socket必定会有绑定一个连接,在普通的BIO(阻塞式IO)中,需要有三次握手,然后一般的socket编程就是这样的形式。
Socket服务器端流程如下:加载套接字->创建监听的套接字->绑定套接字->监听套接字->处理客户端相关请求。
Socket客户端同样需要先加载套接字,然后创建套接字,不过之后不用绑定和监听了,而是直接连接服务器,发送相关请求。
他们一直就占用这个连接,如果有信息发送,那么就响应,否则就一直阻塞着。如果有多连接,那么就要使用多线程,一个线程处理一个连接,在连接还少的情况下,是允许的,但如果同时处理的连接过多比如说1000,那么在win平台上就会遇到瓶颈了如果2000,那么在linux上就遇到瓶颈了,因为在不同的平台上每一个进程能够创建的线程数是有限度的,并且过多的线程必将会引起系统对线程调度的效率问题,再怎么也要保证线程优先队列,阻塞队列;假设一千个线程,一个线程最少一兆的栈大小,对内存也是一个很大的消耗。
总之阻塞式的IO是:一连接<一一一>一线程 。
然后出现了NIO,在java1.4引入了java.nio包,java new I/O。引入了操作系统中常用的缓冲区和通道等概念。
缓冲区: 在操作系统中缓冲区是为了解决CPU的计算速度和外设输入输出速度不匹配的问题,因为外设太慢了,如果没有缓冲区,那么CPU在外设输入的时候就要一直等着,就会造成CPU处理效率的低下,引入了缓冲之后,外设直接把数据放到缓冲中,当数据传输完成之后,给CPU一个中断信号,通知CPU:“我的数据传完了,你自己从缓冲里面去取吧”。如果是输出也是一样的道理。
通道: 那么通道用来做什么呢?其实从他的名字就可以看出,它就是一条通道,您想传递出去的数据被放置在缓冲区中,然后缓冲区中怎么从哪里传输出去呢?或者外设怎么把数据传输到缓冲中呢?这里就要用到通道。它可以进一步的减少CPU的干预,同时更有效率的提高整个系统的资源利用率,例如当CPU要完成一组相关的读操作时,只需要向I/O通道发送一条指令,以给出其要执行的通道程序的首地址和要访问的设备,通道执行通道程序便可以完成CPU指定的I/O任务。
选择器: 另外一项创新是选择器,当我们使用通道的时候也许通道没有准备好,或者有了新的请求过来,或者线程遇到了阻塞,而选择器恰恰可以帮助CPU了解到这些信息,但前提是将这个通道注册到了这个选择器。
下面一个例子是我看过的一个讲述的很贴切的例子: 一辆从 A 开往 B 的公共汽车上,路上有很多点可能会有人下车。司机不知道哪些点会有哪些人会下车,对于需要下车的人,如何处理更好? 1. 司机过程中定时询问每个乘客是否到达目的地,若有人说到了,那么司机停车,乘客下车。 ( 类似阻塞式 ) 2. 每个人告诉售票员自己的目的地,然后睡觉,司机只和售票员交互,到了某个点由售票员通知乘客下车。 ( 类似非阻塞 ) 很显然,每个人要到达某个目的地可以认为是一个线程,司机可以认为是 CPU 。在阻塞式里面,每个线程需要不断的轮询,上下文切换,
以达到找到目的地的结果。而在非阻塞方式里,每个乘客 ( 线程 ) 都在睡觉 ( 休眠 ) ,只在真正外部环境准备好了才唤醒,这样的唤醒肯定不会阻塞。
阻塞式和非阻塞式IO的更多相关文章
- Java基础知识强化之多线程笔记07:同步、异步、阻塞式、非阻塞式 的联系与区别
1. 同步: 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回.但是一旦调用返回,就必须先得到返回值了. 换句话话说,调用者主动等待这个"调用"的结果. 对于 ...
- 如何解读 Java IO、NIO 中的同步阻塞与同步非阻塞?
原文链接:如何解读 Java IO.NIO 中的同步阻塞与同步非阻塞? 一.前言 最近刚读完一本书:<Netty.Zookeeper.Redis 并发实战>,个人觉得 Netty 部分是写 ...
- Verilog HDL中阻塞语句和非阻塞语句的区别
在Verilog中有两种类型的赋值语句:阻塞赋值语句(“=”)和非阻塞赋值语句(“<=”).正确地使用这两种赋值语句对于Verilog的设计和仿真非常重要. Verilog语言中讲的阻塞赋值与非 ...
- Linux下同步模式、异步模式、阻塞调用、非阻塞调用总结
转自:http://www.360doc.com/content/13/0117/12/5073814_260691714.shtml 同步和异步:与消息的通知机制有关. 本质区别 现实例子 同步模式 ...
- socket异步通信-如何设置成非阻塞模式、非阻塞模式下判断connect成功(失败)、判断recv/recvfrom成功(失败)、判断send/sendto
socket异步通信-如何设置成非阻塞模式.非阻塞模式下判断connect成功(失败).判断recv/recvfrom成功(失败).判断send/sendto 博客分类: Linux Socket s ...
- 多态设计 zen of python poem 显式而非隐式 延迟赋值
总结 1.python支持延迟赋值,但是给调用者带来了困惑: 2.显式而非隐式,应当显式地指定要初始化的变量 class Card: def __init__(self, rank, suit): s ...
- [Python 多线程] Lock、阻塞锁、非阻塞锁 (八)
线程同步技术: 解决多个线程争抢同一个资源的情况,线程协作工作.一份数据同一时刻只能有一个线程处理. 解决线程同步的几种方法: Lock.RLock.Condition.Barrier.semapho ...
- Spring学习(1):侵入式与非侵入式,轻量级与重量级
一. 引言 在阅读spring相关资料,都会提到Spring是非侵入式编程模型,轻量级框架,那么就有必要了解下这些概念. 二. 侵入式与非侵入式 非侵入式:使用一个新的技术不会或者基本不改变原有代码结 ...
- 斐讯面试记录—阻塞Socket和非阻塞Socket
文章出自:http://blog.csdn.net/VCSockets/ 1.TCP中的阻塞Socket和非阻塞Socket 阻塞与非阻塞是对一个文件描述符指定的文件或设备的两种工作方式. 阻塞的意思 ...
随机推荐
- HDU 1159 Common Subsequence 公共子序列 DP 水题重温
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1159 Common Subsequence Time Limit: 2000/1000 MS (Jav ...
- S2SH+Hibernate search出现的问题
一 java.lang.NoSuchMethodError: org.hibernate.engine.transaction.spi.TransactionEnvironment.getJtaPl ...
- Java-工厂设计模式
引言: 工厂设计模式分为三种: 简单工厂 工厂方法 抽象工厂 联想四种情况 (1).还没有工厂时代:假如还没有工业革命,如果一个客户要一件产品,一般的做法是客户去创建一件产品,然后拿来用. (2).简 ...
- RTB日志分析MR程序设计
到新公司三个月了,上个月做的是Beacon项目,详细的设计思想还没有写文档.这两周开始搞Hadoop,开始阅读相关论文.开始编写MR程序.开始写java,大学时用java较多,工作后就一直在用c/c+ ...
- JDK8新特性之Lambda表达式
Lambda表达式主要是替换了原有匿名内部类的写法,也就是简化了匿名内部类的写法.lambda语法结构: (参数1,参数2...)->{重写方法的内容,不定义方法名} 先看一个使用匿名内部类定义 ...
- Java基础知识强化之IO流笔记27:FileInputStream读取数据一次一个字节数组byte[ ]
1. FileInputStream读取数据一次一个字节数组byte[ ] 使用FileInputStream一次读取一个字节数组: int read(byte[] b) 返回值:返回值其实是实际 ...
- Android(java)学习笔记196:Android中Menu的使用(静态和动态)
1.使用xml定义Menu(静态方法) 菜单资源文件必须放在res/menu目录中.菜单资源文件必须使用<menu>标签作为根节点.除了<menu>标签外,还有另外两个标签用于 ...
- PHP表单验证内容是否为空
内容为空效果图为: 填写内容效果图: 下面是验证程序的代码: <!doctype html> <html> <head> <meta http-equiv=& ...
- nginx介绍及安装
nginx(Engine x) 静态的www软件 特点: 配置简单 高并发,1-2w,基于异步IO模型(epoll,kqueue) 占用资源少 ...
- jquery插件select2事件不起作用(select2-3.5.4)
jquery插件select2事件不起作用 >>>>>>>>>>>>>>>>>>>&g ...