Java教程

一次带你搞懂Java中的BIO|NIO|AIO,你也可以轻松玩转!

本文主要是介绍一次带你搞懂Java中的BIO|NIO|AIO,你也可以轻松玩转!,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
# BIO Java中BIO也成为同步阻塞IO。 同步阻塞IO模式下,服务器实现模式为一个连接对应一个线程,即:有连接请求从客户端发起时,服务器端就需要创建一个线程进行处理,如果有大量连接时,服务器就需要创建大量线程进行处理。当然可以通过线程池机制改善。 阻塞IO适用场景为:连接数较小且固定的架构模式,这种方式对服务器资源要求比较高,并发局限于应用中,不建议在生产环境使用。 # NIO(非阻塞IO) Java中非阻塞式IO,也叫同步非阻塞IO,其通过通道和缓冲区来读写数据。通过选择器注册和获取已准备好的感兴趣的通道事件。读数据时,有多少数据就读多少数据,读完立即返回,如SocketChannel和ServerSocketChannel、Selector等。 NIO本身是基于事件驱动思想来完成的,其主要想解决的是BIO的大并发问题。NIO基于Reactor,当socket有流可读或可写入socket时,操作系统会相应的通知引用程序进行处理,应用再将流读取到缓冲区或写入操作系统。 也就是说,这个时候,已经不是一个连接就要对应一个处理线程了,而是有效的请求,对应一个线程,当连接没有数据时,是没有工作线程来处理的。 NIO的最重要的地方是,当一个连接创建后,不需要对应一个线程,这个连接会被注册到多路复用器上面。所以,所有的连接只需要一个线程就可以搞定,当这个线程中的多路复用器进行轮询的时候,发现连接上有请求的话,才开启一个线程进行处理,也就是一个请求一个线程模式。 在NIO的处理方式中,当一个请求来的话,开启线程进行处理,可能会等待后端应用的资源(JDBC连接等),其实这个线程就被阻塞了,当并发上来的话,还是会有BIO一样的问题。 Java NIO 由以下几个核心部分组成: - Channels - Buffers - Selectors 虽然Java NIO 中除此之外还有很多类和组件,但是,Channel,Buffer和Selector构成了核心的API。其它组件,如Pipe和FileLock,只不过是与三个核心组件共同使用的工具类。 读者推荐:[并发编程学习笔记](https://mp.weixin.qq.com/s/B6YzNvAopKkFxKf-1Q_NcA)! # Channel vs Buffer Channel和Buffer:基本上,所有的IO在NIO中都从一个Channel开始。Channel有点像流,数据可以从Channel读到Buffer中,也可以从Buffer写到Channel中。如:Channel和Buffer有好几种类型。下面是JAVA NIO中的一些主要Channel的实现:FileChannel、DatagramChannel、SocketChannel、ServerSocketChannel。这些通道涵盖了UDP 和 TCP 网络IO,以及文件IO。 ![](https://upload-images.jianshu.io/upload_images/24630328-884613e4f0d8b8bc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) Java NIO里关键的Buffer实现:ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer、MappedByteBuffer(内存映射文件 )。这些Buffer覆盖了能通过IO发送的基本数据类型:byte,short,int,long,float,double和char。 Channel和Buffer使用案例:改代码以随机读写方式打开nio-data.txt文件,一个字节一个字节的把文件内容读入新分配的buf缓存中。 ![](https://upload-images.jianshu.io/upload_images/24630328-6798f47e7f66cca5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) # Selector Selector允许单线程处理多个 Channel。如果应用打开了多个**连接**(通道),但每个连接的流量都很低,使用Selector就会很方便。例如,在一个聊天服务器中。单线程中使用一个Selector处理3个Channel的图示: ![](https://upload-images.jianshu.io/upload_images/24630328-6ca9da4611d26c77.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 要使用Selector,得向Selector注册Channel,然后调用它的select()方法。**这个方法会一直阻塞**到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等。 Selector使用案例:该案例使用Selector已订阅事件的通道进行选择,当订阅事件发生时即可另行开辟线程处理该通道事件。 ![](https://upload-images.jianshu.io/upload_images/24630328-1b5d10b447bbf5dc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) # AIO(异步IO) Java中的异步IO,通过Future轮询和Callback回调两种方式来使用。 与NIO不同,当进行读写操作时,异步IO情况下,我们只需要直接调用API的read或write方法即可。这两个操作都是异步的。 - 对于读操作而言,当有流可读时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序; - 对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。 即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。在JDK1.7中,这部分内容被称作NIO.2,主要在java.nio.channels包下增加了下面四个异步通道:AsynchronousSocketChannel、 AsynchronousServerSocketChannel、AsynchronousFileChannel、AsynchronousDatagramChannel。 # Future轮询模式 典型的Java通道类有AsynchronousFileChannel。来看一个例子: ![](https://upload-images.jianshu.io/upload_images/24630328-26acaa3cc33a3868.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 该案例通过异步IO通道AsynchronousFileChannel将文件foobar.txt的内容读入buffer中,在通过Future获取结果。Java将读取文件的操作交给操作系统底层去做,自己只需要知道文件是否读取完毕就好了。其实底层JVM为执行这个任务创建了线程池和通道组。具体可以参考AsynchronousFileChannel的官方说明: > An AsynchronousFileChannel is associated with a thread pool to which tasks are submitted to handle I/O events and dispatch to completion handlers that consume the results of I/O operations on the channel. The completion handler for an I/O operation initiated on a channel is guaranteed to be invoked by one of the threads in the thread pool (This ensures that the completion handler is run by a thread with the expected identity). Where an I/O operation completes immediately, and the initiating thread is itself a thread in the thread pool, then the completion handler may be invoked directly by the initiating thread. When an AsynchronousFileChannel is created without specifying a thread pool then the channel is associated with a system-dependent default thread pool that may be shared with other channels. The default thread pool is configured by the system properties defined by the AsynchronousChannelGroup class. # Callback回调模式 Future其实本质上还是轮循的方式,回调式才是真正的AIO。其基本思想是主线程注册一个**CompletionHanlder**执行IO操作。**CompletionHanlde**将带着IO操作的结果返回到主线程中,这个结果会触发它自己的completed或者failed方法(需要重写这两个方法): 1. void completed(V result, A attachment) - executes if a task completes with a result of type V. 2. void failed(Throwable e, A attachment) - executes if the task fails to complete due to Throwable e. callback回调案例: ![](https://upload-images.jianshu.io/upload_images/24630328-8c706b39b1e3e19b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 上面的例子是基于文件的AsynchronousFileChannel,但是基于网络套接字的 AsynchronousServerSocketChannel和AsynchronousSocketChannel也是一样的模式。
这篇关于一次带你搞懂Java中的BIO|NIO|AIO,你也可以轻松玩转!的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!