https://gitee.com/jly521/NioAio.git NIO、AIO代码举例地址
- 从进程级通信的维度讨论时, 阻塞和同步(非阻塞和异步)就是一对同义词, 且需要针对发送方和接收方作区分对待。
- 发送方阻塞/非阻塞(同步/异步)和接收方的阻塞/非阻塞(同步/异步) 是互不影响的。
#############################我的理解
同步和异步(宏观表现):
- 异步能主动通知你,不用你不停的轮询
- 同步的含义是,你是否需要亲自去处理数据
阻塞非阻塞(具体实现):
- 调用不能直接返回结果,所采取的策略(等还是不等)
BIO(同步阻塞):
- 比如发起读入操作,如果获取不到就会阻塞等待返回结果,整个程序挂起。
NIO(同步非阻塞):
- channel、selector、buffer
- 比如发起读入操作,调用handler
- 如果获取不到就会返回读取不到状态(比如被锁),整个程序挂起,过一段时间轮询好了没
- 如果获取到读入缓存,开启读取动作
- 使用 select轮询就是同步
- 每次从选中的通道读取数据可以设置阻塞和非阻塞策略,读入缓存
AIO,即NIO2.0(异步非阻塞):
- 比如发起读入操作,
- 如果读取不到,根本不会调用handler
- 如果获取到读入缓存,调用handler处理
- aio 接收客户端请求才去的是读入完成后回调处理函数,所以是异步
- 创建的AsynchronousSocketChannel通道,名字不难看出是异步通道(非阻塞)
@@@@@@@@@@@@@@@@@@@@@@@@@@
IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。
BIO
- 在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式
- 需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求
- 而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行。
伪异步I/O编程
- 采用线程池和任务队列可以实现一种叫做伪异步的I/O通信框架。
NIO
- NIO本身是基于事件驱动思想来完成的,其主要想解决的是BIO的大并发问题:
- 将每一个客户端请求分配给一个线程来单独处理。
- 操作系统本身也对线程的总数有一定的限制。
- 如果客户端的请求过多,服务端程序可能会因为不堪重负而拒绝客户端的请求,甚至服务器可能会因此而瘫痪。
BIO与NIO一个比较重要的不同
- 是我们使用BIO的时候往往会引入多线程,每个连接一个单独的线程;
- 而NIO则是使用单线程或者只使用少量的多线程,每个连接共用一个线程。
- NIO的最重要的地方是当一个连接创建后,不需要对应一个线程,这个连接会被注册到多路复用器上面
- 所以所有的连接只需要一个线程就可以搞定,
- 当这个线程中的多路复用器进行轮询的时候,发现连接上有请求的话,才开启一个线程进行处理,也就是一个请求一个线程模式
- 在NIO的处理方式中,
- 当一个请求来的话,开启线程进行处理,可能会等待后端应用的资源(JDBC连接等),其实这个线程就被阻塞了,
- 当并发上来的话,还是会有BIO一样的问题。
AIO
- 与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。
- 这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;
- 即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。
汇总图:
先来个例子理解一下概念,以银行取款为例:
- 同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读写);
- 异步 : 委托一小弟拿银行卡到银行取钱,然后给你(使用异步IO时,Java将IO读写委托给OS处理,需要将数据缓冲区地址和大小传给OS(银行卡和密码),OS需要支持异步IO操作API);
- 阻塞 : ATM排队取款,你只能等待(使用阻塞IO时,Java调用会一直阻塞到读写完成才返回);
- 非阻塞 : 使用非阻塞IO时,如果不能读写Java调用会马上返回,当IO事件分发器会通知可读写时再继续进行读写,不断循环直到读写完成。
Java对BIO、NIO、AIO的支持:
- Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,
- 即客户端有连接请求时服务器端就需要启动一个线程进行处理,
- 如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
- Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,
- 即客户端发送的连接请求都会注册到多路复用器上,
- 多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
- Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,
- 客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,
BIO、NIO、AIO适用场景分析:
- BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
- NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
- AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
同步和异步是针对应用程序和内核的交互而言的。
- 同步/异步是在时间上强调处理事情的结果/机会成本的两种处理策略;
阻塞和非阻塞是针对于进程在访问数据的时候
- 阻塞方式下读取或者写入函数将一直等待,
- 而非阻塞方式下,读取或者写入函数会立即返回一个状态值。
同步/异步是宏观上(进程间通讯,通常表现为网络IO的处理上),
- 阻塞/非阻塞是微观上(进程内数据传输,通常表现为对本地IO的处理上);
- 阻塞和非阻塞是同步/异步的表现形式
来源:oschina
链接:https://my.oschina.net/u/3847203/blog/2353873