同步与异步:同步是一种可靠的有序运行机制,当我们进行同步操作时,后续的任务是等待当前调用返回,才会进行下一步;而异步则相反,其他任务不需要等待当前返回,通常依靠事件,回调等机制来实现任务间次序关系。
阻塞和非阻塞:在进行阻塞操作时,当前线程会处于阻塞状态,无法从事其他任务,只有当条件就绪才能继续,比如ServerSocket新链接建立完毕,或者数据读取,写入操作完成,而非阻塞则是不管IO操作是否结束,直接返回,相应操作在后台继续处理。
IO流(同步、阻塞),前面的文章已经详细介绍过,想知道的可以去前面查阅。
NIO(同步、非阻塞)
NIO的三个主要组成部分:Channel(通道),Buffer(缓冲区),Selector(选择器)
Channel(通道):是一个对象,可以通过他读取和写入数据,可以把它看做是IO中的流,不同的是
-Channel是双向的,即可以读又可以写,而流水单向的
-Channel可以进行异步读写
-Channel的读写必须通过Buffer对象。
Channel的类型:
-FileChannel:从文件读取数据
-DatagramChannel:读写UDP网络协议数据
-SocketChannel:读写TCP网络协议数据
-ServerSocketChannel:可以监听TCP连接
Buffer(缓冲区):是一个对象,包含了一些药写入或者读到Stream对象的。应用程序不能直接对Channel进行读写操作,而必须通过Buffer来进行,即Channel是通过Buffer来读写数据的
使用Buffer读写数据一般遵循以下四个步骤:
1、写入数据到Buffer
2、调用flip()方法
3、从Buffer中读取数据
4、调用clear()方法或者conpact()方法
Buffer的类型:
-ByteBuffer
-CharBuffer
-DoubleBuffer
-FloatBuffer
-IntBuffer
-LongBuffer
-ShortBuffer
Selector(选择器):是一个对象,他可以注册到很多Channel上,监听各个Channel上发生的事件,并且能够根据事件情况决定Channel读写。这样,通过一个线程管理多个Channel,就可以处理大量网络连接。
优点:有了Selector,我们就可以利用一个线程来处理所有的channels。线程之间的切换对操作系统来说代价上很高的,并且每个线程也会占用一定的系统资源。所以对系统来说使用的线程越少越好。
使用方式:
1、创建一个Selector
2、注册Channel到Selector,调用channel.register()方法
注意:注册到Channel必须设置成异步模式才可以,否则异步IO就无法工作,这就意味着我们不能把一个FileChannel注册到Selector,因为FileChannel没有异步模式,但是网络编程中的SocketChannel是可以的。
注册后的返回值是一个SelectionKey。SelectionKey代表这个通道在此Selector上注册,当某个Selector通知您某个传入事件时,它是通过提供对应于该事件的SelectionKey来进行的。
SelectionKey包含如下属性:
Interest set:你要选择的感兴趣的事件的集合
ready set:通道已经准备就绪的集合
Channel:注册的Channel
Selector:获得Selector
attached object:可以将一个对象或者更多信息attach到SelectionKey上
NIO多路复用:
主要步骤和元素:
1、通过Selector.open()创建一个Selector,作为类似调度员的角色
2、创建一个ServerSocketChannel,并且向Selector注册,通过指定SelectionKey.OP_ACCEPT告诉调度员,他关注的是新的连接请求
3、Selector阻塞在select操作,当有Channel发生接入请求,就会被唤醒
4、在具体的方法中,通过SocketChannel和Buffer进行数据操作。