io,读写,指的是内存,
读是内存从文件网络等读取数据
写是内存写数据到文件网络等
bio(同步阻塞io)
叫一个线程停留在一个水壶那,直到这个水壶烧开,才去处理下一个水壶
一个请求创建一个线程
nio(java的nio就是linux的多路复用io)Netty、Dubbo、ZooKeeper等都是基于NIO方式实现
- bio面向字节流,nio面向块(buffer)
- 直接内存(非堆内存),减少拷贝次数(原来是堆内存拷贝到非堆内存,在拷贝到缓冲区)
- 内核和磁盘io通过channel,不占用cpu资源(原来调用io资源需要cpu参与)
- 多路复用器selector(检查多个channel是否准备好),select,epoll
所有数据都通过Buffer对象处理,所以,您永远不会将字节直接写入到Channel中,相反,您是将数据写入到Buffer中;同样,您也不会从Channel中读取字节,而是将数据从Channel读入Buffer,再从Buffer获取这个字节
异步 I/O 的一个优势在于,它允许您同时根据大量的输入和输出执行 I/O。同步程序常常要求助于轮询,或者创建许许多多的线程以处理大量的连接。使用异步 I/O,您可以监听任何数量的通道上的事件,不用轮询,也不用额外的线程。
Selector它可以注册到很多个Channel上,监听各个Channel上发生的事件,并且能够根据事件情况决定Channel读写。这样,通过一个线程管理多个Channel,就可以处理大量网络连接了。
一旦调用了select()方法,它就会返回一个数值,表示一个或多个通道已经就绪,然后你就可以通过调用selector.selectedKeys()方法返回的SelectionKey集合来获得就绪的Channel。请看演示方法:
Set selectedKeys = selector.selectedKeys();
当你通过Selector注册一个Channel时,channel.register()方法会返回一个SelectionKey对象,这个对象就代表了你注册的Channel。这些对象可以通过selectedKeys()方法获得。你可以通过迭代这些selected key来获得就绪的Channel
AIO(异步非阻塞,无需轮询,线程结束后主动通知)
为每个水壶上面装了一个开关,水烧开之后,水壶会自动通知我水烧开了。
同步&异步
同步
发送一个请求,等待返回,再发送下一个请求,同步可以避免出现死锁,脏读的发生。
异步
发送一个请求,不等待返回,随时可以再发送下一个请求,可以提高效率,保证并发。
阻塞&非阻塞
阻塞
传统的IO流都是阻塞式的。也就是说,当一个线程调用read()或者write()方法时,该线程将被阻塞,直到有一些数据读读取或者被写入,在此期间,该线程不能执行其他任何任务。在完成网络通信进行IO操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量的客户端时,性能急剧下降。
非阻塞
JavaNIO是非阻塞式的。当线程从某通道进行读写数据时,若没有数据可用时,该线程会去执行其他任务。线程通常将非阻塞IO的空闲时间用于在其他通道上执行IO操作,所以单独的线程可以管理多个输入和输出通道。因此NIO可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户端。
---------------------------------------------------
基本概念
缓冲区
调用read,DMA拷贝到内核缓冲区,再拷贝到用户缓冲区
硬件设备通常不能直接访问用户空间(虚拟内存地址)
虚拟内存(需要映射)
通过内存映射,减少了内核与用户空间数据的拷贝
虚拟内存分页,存在于外部磁盘存储,MMU管理内存映射关系,通过页错误来替换内存与磁盘的页
文件io
用户使用read和write操作内存,在内核空间 的文件系统页与用户空间的内存区之间移动数据,一次以上的拷贝操作几乎总是免不了的
文件锁定
流io
就绪型io
选择器
缓冲区连接通道,通道连接套接字或文件
通道注册到选择器上,注册成功后返回选择键(SelectionKey,包含通道,选择器,感兴趣的操作,ready的集合)(关联通道和是否就绪,调用选择器的select更新就绪状态)
选择器管理着被注册的通道集合的信息和它们的就绪状态,已选择的键的集合
可选择通道:这个抽象类提供了实现通道的可选择性所需要的公共方法,可以指定对 那个选择器而言,那种操作是感兴趣的;FileChannel 对象不是可选择的,因为它们没有继承 SelectableChannel(见图 4-2)。 所有 socket 通道都是可选择的