asdfasdfsaf
JAVA NIO
三个概念:
1, 选择器
2, 选择键
3, 可选择通道
多个可选择通道可以被注册于一个选择器中,该选择器通过轮询每个可选择通道的选择键来判断是否可以进行IO操作。
一个可选择通道是通过选择键来注册到选择器中的。
可选择通道提供的API应该具有:
Register到一个选择器的方法
从上图中可以看到,一个选择器可以被多个可选择通道注册,选择器和可选择通道是通过选择键关联的。
一个键表示了一个特定的可选择通道和一个特定的选择器对象之间的注册关系,一个通道只可能有一个键,观察selectionKey的类方法可以看到:channel()方法和selector()方法。这两个方法很好的表示了selectionKey起到的作用。很容易想到当一个通道准备好时,相应的selectionKey将被置位,当selector进行选择的时候,他通过轮询所有通道的selectionKey来判断哪些通道的哪些操作已经准备好。selectionKey包含了2个集合:interest集合和ready集合。Interest集合表示当某个通道被注册到选择器时,他所关心的IO操作。Ready集合表示,当通道所关心的IO操作已经准备好时,ready将被置位。也就是说,在一次选择过程中,一个通道的ready集合是interest集合的子集。
每一个selector对象维护三个键的集合:
已注册集合:所有注册过的,打开的通道的集合
已选择集合:已注册集合的子集,都是相关的通道被选择器判断为已准备好的(那么必然在interest集合中)。注意,不要把ready集合和该集合混淆。该集合中的每一个键都有一个ready集合,指示了该键所对应通道的已经准备好的IO操作。
已取消集合:当调用cancel()方法,或者关闭一个通道时,将会在该集合中出现。
举例而言:
我们有2个通道被注册到选择器上,这两个通道A,B。A关心读、写。B关心accept操作
在selector被初始化的时候,这两个键就在已注册的集合中了。
在某个时刻,A通道的读IO准备好,写IO准备好。Selector开始选择过程,这时selector就会知道A的读准备好,A的写准备好。这时,由于B没有任何其关心的IO操作准备好,所以已选择的键的集合就只有一个A的键,但是这个键包含了两个IO操作:读、写。这两个IO操作就属于A的ready集合。如果此时,我们将B置为cancel()之后,B的键将被放入已取消集合中。当下一次选择开始后,B将被清除。
什么是选择操作:
1, 检查已取消的集合,所有的该集合中的键将从其他两个集合中移除,通道被注销
2, 已注册的键集合中的键的Interest集合将被检查。以确定在这次选择操作中每个键所关心的操作。检查过后,就可以对interest集合进行改动了。
3, 静态检查过后,OS将会进行查询,以确认每个通道所关心的操作的就绪状态,如果某个通道所关心的操作已就绪,就:
a) 如果当前的键没有在已选择集合中,当前的键的ready集合将被清空。当前通道关心的、并且已经准备好的操作的相对应bit位将在ready集合中被置位。并将该键放入已选择键中
b) 如果已经在已选择集合中,那么该键的ready集合将被更新为通道关心的操作。但是,已经不再是就绪状态的操作并不会被清除。
4, select操作返回的是ready集合在第三步中被修改的键的数量,而不是已选择的键的集合中的通道的总数。返回值不是已准备好的通道的总数,而是从上一个select( )调用之后进入就绪状态的通道的数量。之前的调用中就绪的,并且在本次调用中仍然就绪的通道不会被计入,而那些在前一次调用中已经就绪但已经不再处于就绪状态的通道也不会被计入。这些通道可能仍然在已选择的键的集合中,但不会被计入返回值中。返回值可能是0。
这样设计的原因是有些操作可能仍然在下一次的选择中就绪,这些就绪的键所对应的通道可能还没有完成执行之前选择的键的操作。如果被计入,考虑这样一个情形,在1选择中通道1的读操作准备好,一个线程开始执行该操作。但是主线程的selector立即就开始下一次的选择过程,那么将创建一个新的线程来执行这个通道1的读操作,这时,就出现问题了。
例子:
考虑1个客户端的情况:当客户端建立请求之后,发送请求之前,NIO服务器的某个关心aceept的通道所对应的键将会返回,这时你可以拿到这个channel的句柄,同样的,我们需要将这个句柄注册到选择器上,并告知选择器这个句柄所关心的操作。当下一次选择开始时,如果客户端还没有发送实际的请求报文,那么选择器将返回0,以表示没有任何键准备好。当客户端发送数据后。NIO服务器又开始了新的选择,在选择之后,将返回1,此时这个channel句柄的键的读操作准备就绪,那么将会进行实际的读操作。
当有多个客户端时,10个客户端并发建立连接请求,那么selector将返回10,表示有10个selector准备好。那么已选择的键的集合就有10个,并相应的执行他们的操作。在执行的过程中,如果有几个客户端已经开始发送数据,那么,这些数据将留在通道的缓存中。而同时,随着这些通道的建立,并且被注册。在下一次的选择过程中,选择器将注意到这些缓存中的数据,那么此时,这些通道的读操作就已经准备好,选择器将返回这写准备好的键,并执行相应的方法来处理。
三个概念:
1, 选择器
2, 选择键
3, 可选择通道
多个可选择通道可以被注册于一个选择器中,该选择器通过轮询每个可选择通道的选择键来判断是否可以进行IO操作。
一个可选择通道是通过选择键来注册到选择器中的。
可选择通道提供的API应该具有:
Register到一个选择器的方法
从上图中可以看到,一个选择器可以被多个可选择通道注册,选择器和可选择通道是通过选择键关联的。
一个键表示了一个特定的可选择通道和一个特定的选择器对象之间的注册关系,一个通道只可能有一个键,观察selectionKey的类方法可以看到:channel()方法和selector()方法。这两个方法很好的表示了selectionKey起到的作用。很容易想到当一个通道准备好时,相应的selectionKey将被置位,当selector进行选择的时候,他通过轮询所有通道的selectionKey来判断哪些通道的哪些操作已经准备好。selectionKey包含了2个集合:interest集合和ready集合。Interest集合表示当某个通道被注册到选择器时,他所关心的IO操作。Ready集合表示,当通道所关心的IO操作已经准备好时,ready将被置位。也就是说,在一次选择过程中,一个通道的ready集合是interest集合的子集。
每一个selector对象维护三个键的集合:
已注册集合:所有注册过的,打开的通道的集合
已选择集合:已注册集合的子集,都是相关的通道被选择器判断为已准备好的(那么必然在interest集合中)。注意,不要把ready集合和该集合混淆。该集合中的每一个键都有一个ready集合,指示了该键所对应通道的已经准备好的IO操作。
已取消集合:当调用cancel()方法,或者关闭一个通道时,将会在该集合中出现。
举例而言:
我们有2个通道被注册到选择器上,这两个通道A,B。A关心读、写。B关心accept操作
在selector被初始化的时候,这两个键就在已注册的集合中了。
在某个时刻,A通道的读IO准备好,写IO准备好。Selector开始选择过程,这时selector就会知道A的读准备好,A的写准备好。这时,由于B没有任何其关心的IO操作准备好,所以已选择的键的集合就只有一个A的键,但是这个键包含了两个IO操作:读、写。这两个IO操作就属于A的ready集合。如果此时,我们将B置为cancel()之后,B的键将被放入已取消集合中。当下一次选择开始后,B将被清除。
什么是选择操作:
1, 检查已取消的集合,所有的该集合中的键将从其他两个集合中移除,通道被注销
2, 已注册的键集合中的键的Interest集合将被检查。以确定在这次选择操作中每个键所关心的操作。检查过后,就可以对interest集合进行改动了。
3, 静态检查过后,OS将会进行查询,以确认每个通道所关心的操作的就绪状态,如果某个通道所关心的操作已就绪,就:
a) 如果当前的键没有在已选择集合中,当前的键的ready集合将被清空。当前通道关心的、并且已经准备好的操作的相对应bit位将在ready集合中被置位。并将该键放入已选择键中
b) 如果已经在已选择集合中,那么该键的ready集合将被更新为通道关心的操作。但是,已经不再是就绪状态的操作并不会被清除。
4, select操作返回的是ready集合在第三步中被修改的键的数量,而不是已选择的键的集合中的通道的总数。返回值不是已准备好的通道的总数,而是从上一个select( )调用之后进入就绪状态的通道的数量。之前的调用中就绪的,并且在本次调用中仍然就绪的通道不会被计入,而那些在前一次调用中已经就绪但已经不再处于就绪状态的通道也不会被计入。这些通道可能仍然在已选择的键的集合中,但不会被计入返回值中。返回值可能是0。
这样设计的原因是有些操作可能仍然在下一次的选择中就绪,这些就绪的键所对应的通道可能还没有完成执行之前选择的键的操作。如果被计入,考虑这样一个情形,在1选择中通道1的读操作准备好,一个线程开始执行该操作。但是主线程的selector立即就开始下一次的选择过程,那么将创建一个新的线程来执行这个通道1的读操作,这时,就出现问题了。
例子:
考虑1个客户端的情况:当客户端建立请求之后,发送请求之前,NIO服务器的某个关心aceept的通道所对应的键将会返回,这时你可以拿到这个channel的句柄,同样的,我们需要将这个句柄注册到选择器上,并告知选择器这个句柄所关心的操作。当下一次选择开始时,如果客户端还没有发送实际的请求报文,那么选择器将返回0,以表示没有任何键准备好。当客户端发送数据后。NIO服务器又开始了新的选择,在选择之后,将返回1,此时这个channel句柄的键的读操作准备就绪,那么将会进行实际的读操作。
当有多个客户端时,10个客户端并发建立连接请求,那么selector将返回10,表示有10个selector准备好。那么已选择的键的集合就有10个,并相应的执行他们的操作。在执行的过程中,如果有几个客户端已经开始发送数据,那么,这些数据将留在通道的缓存中。而同时,随着这些通道的建立,并且被注册。在下一次的选择过程中,选择器将注意到这些缓存中的数据,那么此时,这些通道的读操作就已经准备好,选择器将返回这写准备好的键,并执行相应的方法来处理。
还没人赞这篇日记