JAVA 非阻塞IO原理
来源:互联网 发布:应收账款软件标志 编辑:程序博客网 时间:2024/06/05 01:17
1. 基本概念
IO是主存和外部设备(硬盘、终端和网络等)传输数据的过程。IO是操作系统的底层功能实现,底层通过I/O指令进行完成。
2. nio简介
nio是java New IO的简称(并不只是指非阻塞IO),在jdk1.4里提供的新api。Sun官方标榜的特性如下:– 为所有的原始类型提供(Buffer)缓存支持。
– 字符集编码解码解决方案。
– Channel:一个新的原始I/O抽象。
– 支持锁和内存映射文件的文件访问接口。
– 提供多路(non-bloking)非阻塞式的高伸缩性网络I/O。
详细介绍可见 http://www.iteye.com/topic/834447
3. 非阻塞 IO
何为阻塞、何为非阻塞,非阻塞原理。
何为阻塞?
一个常见的网络IO通讯流程如下:
何为非阻塞?
下面有个隐喻:
一辆从 A 开往 B 的公共汽车上,路上有很多点可能会有人下车。司机不知道哪些点会有哪些人会下车,对于需要下车的人,如何处理更好?
1. 司机过程中定时询问每个乘客是否到达目的地,若有人说到了,那么司机停车,乘客下车。 ( 类似阻塞式 )
2. 每个人告诉售票员自己的目的地,然后睡觉,司机只和售票员交互,到了某个点由售票员通知乘客下车。 ( 类似非阻塞 )
很显然,每个人要到达某个目的地可以认为是一个线程,司机可以认为是 CPU 。在阻塞式里面,每个线程需要不断的轮询,上下文切换,以达到找到目的地的结果。而在非阻塞方式里,每个乘客 ( 线程 ) 都在睡觉 ( 休眠 ) ,只在真正外部环境准备好了才唤醒,这样的唤醒肯定不会阻塞。
socket的操作都有一个共同的结构:
1. Read request
2. Decode request
3. Process service
4. Encode reply
5. Send reply
经典的网络服务的设计如下图,在每个线程中完成对数据的处理:
但这种模式在用户负载增加时,性能将下降非常的快。我们需要重新寻找一个新的方案,保持数据处理的流畅,很显然,事件触发机制是最好的解决办法,当有事件发生时,会触动handler,然后开始数据的处理。
Reactor模式类似于AWT中的Event处理:Reactor模式参与者
1.Reactor 负责响应IO事件,一旦发生,广播发送给相应的Handler去处理,这类似于AWT的thread
2.Handler 是负责非堵塞行为,类似于AWT ActionListeners;同时负责将handlers与event事件绑定,类似于AWT addActionListener
非阻塞的原理
把整个过程切换成小的任务,通过任务间协作完成。
由一个专门的线程来处理所有的 IO 事件,并负责分发
事件驱动机制:事件到的时候触发,而不是同步的去监视事件。
线程通讯:线程之间通过 wait,notify 等方式通讯。保证每次上下文切换都是有意义的。减少无谓的进程切换。
Reactor就是上面隐喻的售票员角色。每个线程的处理流程大概都是读取数据、解码、计算处理、编码、发送响应
如图:
Java的NIO为reactor模式提供了实现的基础机制,它的Selector当发现某个channel有数据时,会通过SlectorKey来告知我们,在此我们实现事件和handler的绑定。
我们来看看Reactor模式代码:
public class Reactor implements Runnable{ final Selector selector; final ServerSocketChannel serverSocket; Reactor(int port) throws IOException { selector = Selector.open(); serverSocket = ServerSocketChannel.open(); InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(),port); serverSocket.socket().bind(address); serverSocket.configureBlocking(false); //向selector注册该channel SelectionKey sk =serverSocket.register(selector,SelectionKey.OP_ACCEPT); logger.debug("-->Start serverSocket.register!"); //利用sk的attache功能绑定Acceptor 如果有事情,触发Acceptor sk.attach(new Acceptor()); logger.debug("-->attach(new Acceptor()!"); } public void run() { // normally in a new Thread try { while (!Thread.interrupted()) { selector.select(); Set selected = selector.selectedKeys(); Iterator it = selected.iterator(); //Selector如果发现channel有OP_ACCEPT或READ事件发生,下列遍历就会进行。 while (it.hasNext()) //来一个事件 第一次触发一个accepter线程 //以后触发SocketReadHandler dispatch((SelectionKey)(it.next())); selected.clear(); } }catch (IOException ex) { logger.debug("reactor stop!"+ex); } } //运行Acceptor或SocketReadHandler void dispatch(SelectionKey k) { Runnable r = (Runnable)(k.attachment()); if (r != null){ // r.run(); } } class Acceptor implements Runnable { // inner public void run() { try { logger.debug("-->ready for accept!"); SocketChannel c = serverSocket.accept(); if (c != null) //调用Handler来处理channel new SocketReadHandler(selector, c); } catch(IOException ex) { logger.debug("accept stop!"+ex); } } }}
以上代码中巧妙使用了SocketChannel的attach功能,将Hanlder和可能会发生事件的channel链接在一起,当发生事件时,可以立即触发相应链接的Handler。
将数据读出后,可以将这些数据处理线程做成一个线程池,这样,数据读出后,立即扔到线程池中,这样加速处理速度:
可参考:
http://www.jdon.com/concurrent/reactor.htm
http://javag.iteye.com/blog/221641
- JAVA 非阻塞IO原理
- 非阻塞IO模式原理
- Java阻塞IO与非阻塞IO
- Java阻塞IO与非阻塞IO
- Java阻塞IO与非阻塞IO
- Java阻塞IO与非阻塞IO
- JAVA 非阻塞式IO
- Java IO:阻塞/非阻塞式IO、同步/异步IO
- Java IO:阻塞/非阻塞式IO、同步/异步IO
- Java中的阻塞和非阻塞IO原理以及各自的优劣
- 阻塞、非阻塞IO
- java 同步阻塞io和异步非阻塞io
- Java-NIO(七):阻塞IO与非阻塞IO
- java之非阻塞IO(NIO)
- java NIO 及 阻塞和非阻塞IO
- JAVA IO 同步与异步、阻塞与非阻塞
- JAVA 中IO总结 之前篇阻塞、非阻塞
- JAVA中IO同步、异步、阻塞、非阻塞
- 荀子 《劝学》
- 从This Handler class should be static or leaks might occur!警告说起
- awk的FS
- AES 加密算法
- 为什么计算机类期刊的影响因子这么低?
- JAVA 非阻塞IO原理
- 经典迭代的算法总结——斐波那契数和辗转相除法
- android开发之Notification_通知栏消息
- 算法导论系列文章之同时查找最大值和最小值
- 忆2013,致2014 -- 一个程序员老总的年终总结之(五)
- jquery ui 简单的 table
- 位域及其内存对齐
- 【九度】题目1000:计算a+b
- ubuntu 命令