`
春花秋月何时了
  • 浏览: 41778 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

JAVA NIO源码分析---总结篇

阅读更多

通过上一篇对JAVA NIO的源码分析,对一些重要的代码实现进行了探究,现将从源码分析中得出的结论总结如下。

一、源码分析流程梳理。

1.Selector.open() 获取选择器的时候,根据不同的操作系统创建Selector实现类,实现类创建了用于保存通道句柄和事件类型的数据结构PollArrayWrapper,如果是Windows系统将会创建一对相互连接的socket通道模拟管道用于唤醒,而Linux对于内核版本>=2.6并且JDK>1.5u9的情况下可以创建更加高效的epoll模式的Selector实现类。并且Linux系统可以直接利用操作系统的管道做到唤醒的功能。

 

2.ServerSocketChannel.register(...)通道注册,根据channel和selector创建了把两者关联起来的SelectionKeyImpl对象,并将其记录到已注册键的集合中,同时将socket句柄以及事件添加至PollArrayWrapper结构中。另外针对操作系统对最大句柄数的限制可能还需要创建更多的线程。

 

3.Selector.select();在执行选择操作之前,首先对已经取消的键集合进行清理,并调整线程数(因最大句柄数限制而创建的helper线程),然后调用操作系统底层的select函数,把检查通道是否就绪的工作移交至操作系统,如果是Windows则是通过轮询的方式进行检测,如果是Linux则可能是select/poll也是轮询或者基于中断的更高效的epoll的方式进行检测,这取决于jdk的版本和内核的版本。当系统底层的select调用返回之后,再次进行对已经取消的键集合进行清理,并返回继上一次select操作之后到本次结束新就绪的通道数量。

 

4.Selector.wakeup(),通过向管道(Windows是互联的socket通道)的sink端写入一个字节来唤醒阻塞在select的调用,并且连续多次的唤醒动作将等同于一次调用。

 

二、相关知识点

1.首先Selector.open()并不是单例模式,当你每次调用该静态方法时候,都返回一个全新的Selector实例。

 

2.Selector能够通过调用configureBlocking来设置是否启用非阻塞模式。其默认为阻塞模式。

 

3.服务端和客户端是否维护着同一份Selector,答案是否定的,服务端和客户端各自维护着一个Selector对象,并且注意在多线程并发的时候,虽然Selector是线程安全的,但是其内部的重要成员集合(registeredKeys、selectedKeys、cancelledKeys)是非线程安全的。如果在多个线程并发地访问一个选择器的键的集合的时候存在任何问题,您可以采取一些步骤来合理地同步访问。

 

4.在执行选择操作时,选择器在 Selector 对象上进行同步,然后是已注册的键的集合,最后是已选择的键的集合,按照这样的顺序。 在多线程的场景中,如果您需要对任何一个键的集合进行更改,不管是直接更改还是其他操作带来的副作用,您都需要首先以相同的顺序,在同一对象上进行同步。锁的过程是非常重要的。如果竞争的线程没有以相同的顺序请求锁,就将会有死锁的潜在隐患。如果您可以确保否其他线程不会同时访问选择器,那么就不必要进行同步了。

 

5.channel.read()函数会返回-1,那么什么时候会读到-1呢?针对服务器端而言,当客户端调用了channel.close()关闭连接时,这时候服务器端返回的读取数是-1,表示已经到了末尾。那么此时需要把对应的SelectionKey给cancel掉,表示selector不再监听这个channel上的读事件,并且关闭channel。

 

6.虽然说一个通道可以被注册到多个选择器上,但对每个选择器而言只能被注册一次。

 

7.当通道关闭时,所有相关的键会自动取消;当选择器关闭时,所有被注册到该选择器的通道都将被注销,并且相关的键将立即被无效化。

 

8.注意select()操作返回值不是已经准备好的通道的总数,而是从上一个select()调用之后进入就绪状态的通道的数量。之前的调用中就绪的,并且在本次调用中仍然就绪的通道不会被计入,而那些在前一次调用中已经就绪但已经不再处于就绪状态的通道也不会计入。这些通道可能仍然在已选择的键的集合中,但不会被计入返回值中,返回值可能是0,这也是为何返回0时,需要continue的原因。

 

9.Selector 类的 close( )方法与 select( )方法的同步方式是一样的,因此也有一直阻塞的可能性。在选择过程还在进行的过程中,所有对 close( )的调用都会被阻塞,直到选择过程结束,或者执行选择的线程进入睡眠。

 

10.当一个通道关闭时,它相关的键也就都被取消了。这并不会影响正在进行的select( ),但这意味着在您调用select( )之前仍然是有效的键,在返回时可能会变为无效。

三、SelectionKey

selectionKey表示了通道(channel)与选择器(selector)之间的注册关系,以及维护了通道的事件。

SelectionKey 包含了两个集合(其实是以整数形式进行编码的byte掩码):

1、 注册的感兴趣的操作集合 即:interestOps集合。

2、已经准备好的操作集合(就绪集合) 即:readyOps集合。

 

Selector维护了三个集合:

1、已经注册的键集合 调用, keys() 
2、已经选择的键集合 调用, selectedKeys() 
3、已经取消的键集合 私有, cancelledKeys

 

这些集合之间的流转关系:

1. 当调用cancel操作的时候,只是把要取消的键加入到了cancelledKeys键集合中,需要等到下次调用select的时候进行才会生效。但是SelectionKey的isValid()会立即回复false。

2. 在操作系统返回就绪操作的通道的时候:

a)如果通道的selectionkey还没有在已经选择的键的集合(selectedKeys)中,那么键的readyOps集合将被清空,然后表示操作系统发现的当前通道已经准备好的操作的比特掩码将被设置。

b)否则,一旦通道的键被放入已经选择的键的集合中时,ready集合不会被清除,而是累积。这就是说,如果之前的状态是ready的操作,本次已经不是ready了,但是他的bit位依然表示是ready,不会被清除。 

从2可以看出我们为什么每次循环selectedKeys的时候都需要调用it.remove().

 

另外:一个channel中的数据没读完(或有数据而不处理),那么,这个channel一直处于就绪状态中,所以每次selector的selectedKeys()方法总能返回与这个channel关联的Selectionkey,然后就会不停地循环select(),除非读完channel中的数据,或者把这个SelectionKey给cancel掉。

 

二、中断select()的方法

select()方法会阻塞住,等待有channel就绪才返回。有时候,希望停止阻塞,中断select方法,让线程继续。

有三种方法。 
1, wakeup()这是一种优雅的方法,立即返回阻塞在select的线程。如果当前没有阻塞在select上,则本次wakeup调用将作用在下一次select操作上,也就是下一次select调用将立即返回无论是否有就绪发生。
2, close()选择器的close被调用,则所有在选择操作中阻塞的线程被唤醒,相关通道被注销,键也被取消。 
3, interrupt() 实际上interrupt并不会中断线程。而是设置线程中断标志。 
然后依然是调用wakeup()。这是因为 Selector 捕获了interruptedException,然后在异常处理中调用了 wakeup() 

 

分享到:
评论

相关推荐

    Java NIO——Selector机制解析三(源码分析)

    本文将深入探讨Java NIO中的Selector机制,并通过源码分析来理解其实现原理。 Selector机制是Java NIO中的核心组件,它允许单线程同时监控多个通道(Channels)的状态变化,例如连接就绪、数据可读或可写等。这种...

    Java nio源码

    Java NIO,全称为New Input/Output,是Java在1.4版本引入的一个新特性,旨在提供一种更高效、更具选择性的I/O模型。...通过分析NIO源码,我们可以深入了解其内部工作原理,进一步优化和调试相关代码。

    Java视频教程 Java游戏服务器端开发 Netty NIO AIO Mina视频教程

    [第4节] JavaNIO流-通道1.flv [第5节] Java NIO流-通道2.flv [第6节] Java NIO流-socket通道操作.flv [第7节] Java NIO流-文件通道操作.flv [第8节] Java NIO流-选择器 .flv [第9节] Java NIO流-选择器操作.flv...

    java nio 聊天室源码

    在这个“java nio 聊天室源码”项目中,开发者使用了NIO来构建一个聊天室应用,以实现用户之间的实时通信。 1. **Java NIO基础** - **通道(Channel)**:在NIO中,数据是通过通道进行传输的,如SocketChannel、...

    java nio聊天室源码

    Java NIO(New IO)是Java 1.4版本引入的一种新的I/O API,它提供了非阻塞I/O操作的能力,极大地提升了Java在...通过分析和学习这个源码,开发者可以深入理解Java NIO的工作原理,并将其应用于实际的网络编程项目中。

    Java NIO原理分析及代码实例

    Java NIO(New IO)是Java 1.4版本引入的一个新API,全称为Non-blocking Input/Output,它提供了一种不同于传统IO的编程模型,传统IO基于块I/O,而NIO则基于通道(Channel)和缓冲区(Buffer)进行数据传输。NIO的...

    java nio im(server+client)

    5. **源码分析** - **服务器源码**:服务器主要代码可能包括设置监听、接受连接、注册选择器、处理选择器返回的事件等部分。 - **客户端源码**:客户端代码则涉及连接服务器、发送数据、接收数据和处理响应等环节...

    Java Socket学习---nio实现阻塞多线程通信

    本篇文章将深入探讨如何使用Java NIO(非阻塞I/O)来实现阻塞多线程通信,这对于高性能服务器端应用尤其重要。我们将会分析`EchoServer.java`、`EchoClient.java`和`SocketUtils.java`这三个文件中的关键知识点。 ...

    java.util源码-Java.util-NIO-Source-code:基本输入和输出,包括带有NIO源代码的java.util读取文件

    Java.util 源码分析与Java NIO (Non-blocking Input/Output) 是Java编程中非常重要的部分,尤其对于深入理解Java I/O系统至关重要。在Java.util包中,我们有许多类用于处理基本的数据结构和工具,如集合、日期时间等...

    基于Java的实例源码-NIO网络框架 xSocket.zip

    - **阅读源码**:通过分析xSocket的源码,可以了解其设计思路和实现细节,提高解决问题的能力。 - **实践项目**:参与实际项目开发,将理论知识应用于实践,提升编程技能。 6. **社区与文档**: - **官方文档**...

    基于Java的实例源码-Skype 4.0 Java版源码及开发文档.zip

    本篇将聚焦于"基于Java的实例源码-Skype 4.0 Java版源码及开发文档.zip",带领读者一探Java技术的深度应用,特别是在即时通讯软件领域的实践。 首先,我们要明确Java作为一种跨平台的编程语言,其强大的可移植性与...

    Java项目开发实践---网络篇

    7. **源码分析** 包含的源码示例可以帮助读者理解如何在实际项目中运用上述概念。通过阅读和运行这些代码,你可以更好地理解网络编程的工作原理,以及如何解决实际问题。 8. **资源管理** 在网络编程中,资源如套...

    NIO项目源码.zip

    通过分析这个NIO项目源码,你可以学习到如何在实际项目中应用NIO技术,理解其设计模式和优化策略,对于提升Java网络编程的能力大有裨益。深入研究NIO的细节,有助于你在开发高效、高并发的服务时做出明智的选择。

    基于Java的实例源码-异步IO框架 Cindy.zip

    5. **Cindy源码分析**:通过阅读和分析Cindy的源码,我们可以深入理解其内部工作原理,包括事件循环的实现、回调机制的调度以及如何优雅地处理并发问题。这对于提升Java并发编程和系统优化的能力非常有价值。 6. **...

    Java-NIO-Netty框架学习

    Java-NIO-Netty框架学习资源目录:【】Netty5.0架构剖析和源码解读【】Netty5用户指南【】Netty_in_Action(第五版-目录修正版)【】Netty_in_Action_v08_MEAP【】Netty_in_Action_v10_MEAP【】Netty_代码分析【】...

    java8集合源码分析-Awesome-Java:真棒-Java

    Java并发编程相关的内容,并发包源码分析等 集合框架 Java集合框架,并发容器,同步容器等 IO框架 Java基础字节流 字符流 NIO等 Java8 Java8语言的行为参数化和流编程等 Java虚拟机 Java虚拟机相关,内存模型,类...

    nioserver.zip_NIO_event driven java_java nio_java nioserv_nioser

    通过分析这些文件,开发者可以学习如何使用Java NIO构建一个事件驱动的服务器,包括如何创建和配置通道、如何注册通道到选择器、如何使用选择器进行多路复用、如何处理读写事件以及如何优化服务器性能等。...

    java nio 多种模式 源码 支持高并发

    源码分析可以帮助我们深入理解NIO的工作原理,从而更好地利用它来优化我们的应用程序。在"nioSamples"这个压缩包中,可能包含了各种NIO场景的示例代码,可以作为学习和调试NIO的参考。 通过学习和实践这些源码,...

    基于Java的实例开发源码-NIO网络框架 xSocket.zip

    源码分析和学习可以涉及以下几个方面: 1. **通道(Channel)和缓冲区(Buffer)**:理解如何创建和使用FileChannel、SocketChannel、ServerSocketChannel等,以及如何通过Buffer进行数据的读写。 2. **选择器...

Global site tag (gtag.js) - Google Analytics