阻塞IO,非阻塞IO,异步IO,IO多路复用,信号驱动;Linux下的IO多路复用函数为select和epoll;Java层面的IO多路复用为NIO,NIO在Linux系统上依靠epoll来实现,Java层面阻塞IO为BIO,非阻塞IO好像没有?异步IO为AIO
BIO的accept和read函数都是阻塞式的,这意味着如果没有客户端连接/客户端连接了却并未发内容的时候,该线程必须放弃cpu时间,在原地阻塞式地等待。那么如果需要实现并发,就必须在多线程的环境下,多线程必然涉及线程的创建和销毁,这是重量级的操作,会大量消耗资源,如果使用线程池可以避免这部分的资源浪费,但只是治标不治本的解决方法,因为阻塞式的等待本质上就是在浪费服务器的资源
为了使得单线程环境下也可以实现并发的操作,提高服务端的处理效率,JDK1.4 之后出现了NIO,实际上就是IO多路复用。NIO最重要的一点在多了ServerSocketChannel这样一个api,使得NIO的read方法和accept方法可以是非阻塞式的。但是直接转化为非阻塞式会有问题,例如socket的丢失,c1与Server连接后,c2需要与Server连接,因为c1没有保存,所以可能产生socket的丢失。为了应对这一情况,NIO使用了Selector,每当有一个新的客户端连接时,socket就会注册在Selector上,并得到一个SelectionKey,之后会有一个单独的线程不断对Selector进行轮询遍历,当需要读取数据时,就会从buffer里面读取。这样就实现了单线程环境下的并发操作。
异步IO,基于回调机制实现,用的不多,Why?
我其实觉得有点像NIO+线程池;别的博客给的定义是IO多路复用监听事件,收到事件后,根据事件的类型发送给某个线程。主要有Reactor,Acceptor,Handler三个对象
然后没提现出封装的特性啊。。
前面还是一样,Reactor负责监听事件,收到事件后分发,如果是建立连接,分发给Acceptor,如果是读写事件,则发给Handler,但Handler不进行业务的处理,只负责读取数据,读取后发送给子线程中的Processor来处理。
这里有个问题是,子线程完成任务之后,要把结果传递给主线程,所以这里涉及到加锁
主Reactor负责监控连接建立事件,从Reactor负责相应事件的工作
都是IO多路复用机制(同步),一旦某个描述符就绪,都能通知程序进行相应的读写
epoll_create() 获得epoll句柄 open一个selector
epoll_ctl() 管理epoll内部的fd register的过程
epoll_wait()监听epoll内所有的fd,返回一个存放活跃fd的链表 selector.select();(把活跃的挑出来)
再次针对BIO NIO Reactor模式进行总结(项目迭代)
原文:https://www.cnblogs.com/donkeyAndConcise/p/15195862.html