java IO模型之 NIO

目录

1.简介:

2.Buffer基本介绍:

3.通道(channel)基本介绍:

4.Selector(选择器)介绍:


1.简介:

NIO是指同步非阻塞,是对BIO(同步阻塞)的改进,它的代码在java.nio及其子包下。

NIO关键的三要素是:Buffer(缓冲区)、Channel(通道)、Selector(选择器)。

以常用的网络TCP通信为例(ServerSocketChannel与SocketChannel),客户端和服务端的线程都不会被阻塞

  1. 客户端(通过Buffer):首先客户端连接服务端的时候,可以通过API finshConnect()进行连接,不会阻塞。读、写也不会阻塞,写的时候直接使用socketChannel.read(buffer),这应该是一个非阻塞方法(待确定,但是通过代码可以发现线程不会停在这里,会继续往下执行)读跟服务端的读类似,也是可以先注册到selector,用selector去选择发生事件的sockerChannel(对应于selector中的selectedKeys)。下面这段话来自网络,有待研究:Client不直接通过通道进行通信,而是在client与通道之间加了Buffer缓冲区(IntBufer、ByteBuffer......,除了boolean类型,别的都提供了对应的buffer,便于根据需要选择对应的Buffer),由Buffer与通道进行数据交互,这样将client解放出来,只有当缓冲区数据准备好的时候(发送数据或者接收数据,准备好),client才会进行处理,如果数据没有准备好,则线程可以去做别的,而不是阻塞在这里
  2. 服务端(通过selector和Buffer):服务端一个线程通过selector选择器,可以处理多个请求(channel), 多个channel通过事件的方式将自己注册到一个selector,采用的是事件驱动的机制,selector监听多个通道的事件,哪个通道发生了某个事件,seletor会选择它,然后线程会去处理(还是通过Buffer与Channel进行通信),当然线程不会阻塞在某个channel上(非阻塞还是通过Buffer实现的)。如果所有通道都没有事件发生,那么线程则都不会去处理,线程会去做别的事情,而不是阻塞在这里等待某个通道发生事件。

 java NIO基本介绍, 一共7条:

NIO与BIO的比较:

2.Buffer基本介绍:

Buffer缓冲区(IntBufer、ByteBuffer......,除了boolean类型,别的都提供了对应的buffer,便于根据需要选择对应的Buffer),此外还有MappedByteBuffer(直接在内存中修改文件内容,修改可以自动映射到文件),Buffer数组等。

下面的例子讲述了怎样使用IntBuffer:  其中的关键点包括flip()操作和clean()操作,flip操作将Buffer数组的指针position的值赋值给limit,然后position变为0,这样就可以从0到limit读取Buffer数组中的数据了。

3.通道(channel)基本介绍:

 FileChannel的buffer和channel都是在客户端,并且Filechannel是从流中获取的。

关于Buffer和channel的注意事项

4.Selector(选择器)介绍:

 

5.NIO非阻塞编程整体流程分析:

下面给出尽量详细的描述(网络TCP通信):

  1. 新建一个ServerSocketChannel,为其设置监听端口,然后设置为非阻塞。新建一个Selector,将ServerSocketChannel注册到该Selector。
  2. 调用selector的select(......)方法(例如select(1000), 停顿1秒钟),查看ServerSocketChannel有没有事件发生,如果没有事件发生(select(......)返回0),则继续select(......),看看有没有事件发生,当然了,线程也可以去干别的,不会阻塞等待事件发生。
  3. 如果如果有事件发生(select(......)返回值大于0),通过selector.selectedKeys()得到事件的集合Set<SelectionKey>,得到这个集合的迭代器Iterator<SelectionKey>,用迭代器遍历事件集合(SelectionKey key = keyIterator.next())根据每个事件的类型(例如读,新的客户端连接)进行处理
  4. 如果是新的客户端连接(key.isAcceptable()),则得到一个新的SockerChannel(SocketChannel socketchannel = serverSockertChannel.accept(), 不会阻塞,因为这里根本不需要等待,直接就是一个新的客户端连接),然后将得到的SocketChannel注册到Selector中(通过register(Selector, int ops, Buffer)方法,其中Selector是要注册到的selector,ops是要注册的操作,比如读、写、已连接、准备连接,如果客户端建立连接后,要发送数据,那么我们这里选择读事件SelectionKey.OP_READ),Buffer是缓冲区,channel必须要关联一个Buffer,在Selector中被以SelectionKey对象的集合的方式存储,一个SelectionKey对应一个SocketChannel。注册方法register(Selector, int ops)的返回值是一个SelectionKey;
  5. 如果是读事件(客户端发送数据过来, (key.isReadable())),通过key反向获取到SocketChannel(key.isAcceptable()的时候,注册到了selector),得到注册的buffer,然后socketChannel.read(buffer)将数据读取到buffer中,这样就得到了客户端的数据(new String(buffer.array()))。
  6. 新来多少个客户端请求,就生成和注册多少个SocketChannel。每次Selector通过select()方法(select()方法本身是阻塞的,但是其有多个重载方法,可以指定方法执行时间,可以遍历一次直接返回等)得到有多少个SocketChannel发生了事件。如果是已经注册的SocketChannel发生了事件(例如可读事件),会将发生事件的SelectionKey放到另外一个集合中,线程遍历这个发生事件的SelectionKey集合,进行处理,可以通过SelectionKey的channel()方法反向获取到SocketChannel,通过得到的SockerChannel,完成业务处理

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值