- 浏览: 469181 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
mrshen:
很棒,在其他大神的博客上理清了思路看懂之后,来lz这里用例子学 ...
RED-BLACK(红黑)树的实现TreeMap源码阅读 -
a939639017:
yanf4j check不下来 ?
Java nio 2.0 AIO -
hellostory:
又是抄来的 - -
mysql分表方案 -
davidluoye:
为什么不说下支持的数据库呢?
模糊查询的优化 -
oliveevilo:
表示没看懂
Synchronized和java.util.concurrent.locks.Lock的区别
按照《Unix网络编程》的划分,IO模型可以分为:阻塞IO、非阻塞IO、IO复用、信号驱动IO和异步IO,按照POSIX标准来划分只分为两类:同步IO和异步IO。如何区分呢?首先一个IO操作其实分成了两个步骤:发起IO请求和实际的IO操作,同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO,因此阻塞IO、非阻塞IO、IO服用、信号驱动IO都是同步IO,如果不阻塞,而是操作系统帮你做完IO操作再将结果返回给你,那么就是异步IO。阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。
Java nio 2.0的主要改进就是引入了异步IO(包括文件和网络),这里主要介绍下异步网络IO API的使用以及框架的设计,以TCP服务端为例。首先看下为了支持AIO引入的新的类和接口:
java.nio.channels.AsynchronousChannel
标记一个channel支持异步IO操作。
java.nio.channels.AsynchronousServerSocketChannel
ServerSocket的aio版本,创建TCP服务端,绑定地址,监听端口等。
java.nio.channels.AsynchronousSocketChannel
面向流的异步socket channel,表示一个连接。
java.nio.channels.AsynchronousChannelGroup
异步channel的分组管理,目的是为了资源共享。一个AsynchronousChannelGroup绑定一个线程池,这个线程池执行两个任务:处理IO事件和派发CompletionHandler。AsynchronousServerSocketChannel创建的时候可以传入一个 AsynchronousChannelGroup,那么通过AsynchronousServerSocketChannel创建的 AsynchronousSocketChannel将同属于一个组,共享资源。
java.nio.channels.CompletionHandler
异步IO操作结果的回调接口,用于定义在IO操作完成后所作的回调工作。AIO的API允许两种方式来处理异步操作的结果:返回的Future模式或者注册CompletionHandler,我更推荐用CompletionHandler的方式,这些handler的调用是由 AsynchronousChannelGroup的线程池派发的。显然,线程池的大小是性能的关键因素。AsynchronousChannelGroup允许绑定不同的线程池,通过三个静态方法来创建:
- public static AsynchronousChannelGroup withFixedThreadPool(int nThreads,
- ThreadFactory threadFactory)
- throws IOException
- public static AsynchronousChannelGroup withCachedThreadPool(ExecutorService executor,
- int initialSize)
- public static AsynchronousChannelGroup withThreadPool(ExecutorService executor)
- throws IOException
public static AsynchronousChannelGroup withFixedThreadPool(int nThreads, ThreadFactory threadFactory) throws IOException public static AsynchronousChannelGroup withCachedThreadPool(ExecutorService executor, int initialSize) public static AsynchronousChannelGroup withThreadPool(ExecutorService executor) throws IOException
需要根据具体应用相应调整,从框架角度出发,需要暴露这样的配置选项给用户。
在介绍完了aio引入的TCP的主要接口和类之后,我们来设想下一个aio框架应该怎么设计。参考非阻塞nio框架的设计,一般都是采用Reactor模式,Reacot负责事件的注册、select、事件的派发;相应地,异步IO有个Proactor模式,Proactor负责 CompletionHandler的派发,查看一个典型的IO写操作的流程来看两者的区别:
Reactor: send(msg) -> 消息队列是否为空,如果为空 -> 向Reactor注册OP_WRITE,然后返回 -> Reactor select -> 触发Writable,通知用户线程去处理 ->先注销Writable(很多人遇到的cpu 100%的问题就在于没有注销),处理Writeable,如果没有完全写入,继续注册OP_WRITE。注意到,写入的工作还是用户线程在处理。
Proactor: send(msg) -> 消息队列是否为空,如果为空,发起read异步调用,并注册CompletionHandler,然后返回。 -> 操作系统负责将你的消息写入,并返回结果(写入的字节数)给Proactor -> Proactor派发CompletionHandler。可见,写入的工作是操作系统在处理,无需用户线程参与。事实上在aio的API 中,AsynchronousChannelGroup就扮演了Proactor的角色。
CompletionHandler有三个方法,分别对应于处理成功、失败、被取消(通过返回的Future)情况下的回调处理:
- public interface CompletionHandler<V,A> {
- void completed(V result, A attachment);
- void failed(Throwable exc, A attachment);
- void cancelled(A attachment);
- }
public interface CompletionHandler<V,A> { void completed(V result, A attachment); void failed(Throwable exc, A attachment); void cancelled(A attachment); }
其中的泛型参数V表示IO调用的结果,而A是发起调用时传入的attchment。
在初步介绍完aio引入的类和接口后,我们看看一个典型的tcp服务端是怎么启动的,怎么接受连接并处理读和写,这里引用的代码都是yanf4j 的aio分支中的代码,可以从svn checkout,svn地址: http://yanf4j.googlecode.com/svn/branches/yanf4j-aio
第一步,创建一个AsynchronousServerSocketChannel,创建之前先创建一个 AsynchronousChannelGroup,上文提到AsynchronousServerSocketChannel可以绑定一个 AsynchronousChannelGroup,那么通过这个AsynchronousServerSocketChannel建立的连接都将同属于一个AsynchronousChannelGroup并共享资源:
- this.asynchronousChannelGroup = AsynchronousChannelGroup
- .withCachedThreadPool(Executors.newCachedThreadPool(),
- this.threadPoolSize);
this.asynchronousChannelGroup = AsynchronousChannelGroup .withCachedThreadPool(Executors.newCachedThreadPool(), this.threadPoolSize);
然后初始化一个AsynchronousServerSocketChannel,通过open方法:
- this.serverSocketChannel = AsynchronousServerSocketChannel
- .open(this.asynchronousChannelGroup);
this.serverSocketChannel = AsynchronousServerSocketChannel .open(this.asynchronousChannelGroup);
通过nio 2.0引入的SocketOption类设置一些TCP选项:
- this.serverSocketChannel
- .setOption(
- StandardSocketOption.SO_REUSEADDR,true);
- this.serverSocketChannel
- .setOption(
- StandardSocketOption.SO_RCVBUF,16*1024);
this.serverSocketChannel .setOption( StandardSocketOption.SO_REUSEADDR,true); this.serverSocketChannel .setOption( StandardSocketOption.SO_RCVBUF,16*1024);
绑定本地地址:
this.serverSocketChannel .bind(new InetSocketAddress("localhost",8080), 100);
其中的100用于指定等待连接的队列大小(backlog)。完了吗?还没有,最重要的监听工作还没开始,监听端口是为了等待连接上来以便accept产生一个AsynchronousSocketChannel来表示一个新建立的连接,因此需要发起一个accept调用,调用是异步的,操作系统将在连接建立后,将最后的结果——AsynchronousSocketChannel返回给你:
- public void pendingAccept() {
- if (this.started && this.serverSocketChannel.isOpen()) {
- this.acceptFuture = this.serverSocketChannel.accept(null,
- new AcceptCompletionHandler());
- } else {
- throw new IllegalStateException("Controller has been closed");
- }
- }
public void pendingAccept() { if (this.started && this.serverSocketChannel.isOpen()) { this.acceptFuture = this.serverSocketChannel.accept(null, new AcceptCompletionHandler()); } else { throw new IllegalStateException("Controller has been closed"); } }
注意,重复的accept调用将会抛出PendingAcceptException,后文提到的read和write也是如此。accept方法的第一个参数是你想传给CompletionHandler的attchment,第二个参数就是注册的用于回调的CompletionHandler,最后返回结果Future<AsynchronousSocketChannel>。你可以对future做处理,这里采用更推荐的方式就是注册一个CompletionHandler。那么accept的CompletionHandler中做些什么工作呢?显然一个赤裸裸的 AsynchronousSocketChannel是不够的,我们需要将它封装成session,一个session表示一个连接(mina里就叫 IoSession了),里面带了一个缓冲的消息队列以及一些其他资源等。在连接建立后,除非你的服务器只准备接受一个连接,不然你需要在后面继续调用pendingAccept来发起另一个accept请求:
- private final class AcceptCompletionHandler implements
- CompletionHandler<AsynchronousSocketChannel, Object> {
- @Override
- public void cancelled(Object attachment) {
- logger.warn("Accept operation was canceled");
- }
- @Override
- public void completed(AsynchronousSocketChannel socketChannel,
- Object attachment) {
- try {
- logger.debug("Accept connection from "
- + socketChannel.getRemoteAddress());
- configureChannel(socketChannel);
- AioSessionConfig sessionConfig = buildSessionConfig(socketChannel);
- Session session = new AioTCPSession(sessionConfig,
- AioTCPController.this.configuration
- .getSessionReadBufferSize(),
- AioTCPController.this.sessionTimeout);
- session.start();
- registerSession(session);
- } catch (Exception e) {
- e.printStackTrace();
- logger.error("Accept error", e);
- notifyException(e);
- } finally {
- <STRONG>pendingAccept</STRONG>();
- }
- }
- @Override
- public void failed(Throwable exc, Object attachment) {
- logger.error("Accept error", exc);
- try {
- notifyException(exc);
- } finally {
- <STRONG>pendingAccept</STRONG>();
- }
- }
- }
private final class AcceptCompletionHandler implements CompletionHandler<AsynchronousSocketChannel, Object> { @Override public void cancelled(Object attachment) { logger.warn("Accept operation was canceled"); } @Override public void completed(AsynchronousSocketChannel socketChannel, Object attachment) { try { logger.debug("Accept connection from " + socketChannel.getRemoteAddress()); configureChannel(socketChannel); AioSessionConfig sessionConfig = buildSessionConfig(socketChannel); Session session = new AioTCPSession(sessionConfig, AioTCPController.this.configuration .getSessionReadBufferSize(), AioTCPController.this.sessionTimeout); session.start(); registerSession(session); } catch (Exception e) { e.printStackTrace(); logger.error("Accept error", e); notifyException(e); } finally { pendingAccept(); } } @Override public void failed(Throwable exc, Object attachment) { logger.error("Accept error", exc); try { notifyException(exc); } finally { pendingAccept(); } } }
注意到了吧,我们在failed和completed方法中在最后都调用了pendingAccept来继续发起accept调用,等待新的连接上来。有的同学可能要说了,这样搞是不是递归调用,会不会堆栈溢出?实际上不会,因为发起accept调用的线程与CompletionHandler回调的线程并非同一个,不是一个上下文中,两者之间没有耦合关系。要注意到,CompletionHandler的回调共用的是 AsynchronousChannelGroup绑定的线程池,因此千万别在CompletionHandler回调方法中调用阻塞或者长时间的操作,例如sleep,回调方法最好能支持超时,防止线程池耗尽。
连接建立后,怎么读和写呢?回忆下在nonblocking nio框架中,连接建立后的第一件事是干什么?注册OP_READ事件等待socket可读。异步IO也同样如此,连接建立后马上发起一个异步read调用,等待socket可读,这个是Session.start方法中所做的事情:
- public class AioTCPSession {
- protected void start0() {
- pendingRead();
- }
- protected final void pendingRead() {
- if (!isClosed() && this.asynchronousSocketChannel.isOpen()) {
- if (!this.readBuffer.hasRemaining()) {
- this.readBuffer = ByteBufferUtils
- .increaseBufferCapatity(this.readBuffer);
- }
- this.readFuture = this.asynchronousSocketChannel.read(
- this.readBuffer, this, this.readCompletionHandler);
- } else {
- throw new IllegalStateException(
- "Session Or Channel has been closed");
- }
- }
- }
public class AioTCPSession { protected void start0() { pendingRead(); } protected final void pendingRead() { if (!isClosed() && this.asynchronousSocketChannel.isOpen()) { if (!this.readBuffer.hasRemaining()) { this.readBuffer = ByteBufferUtils .increaseBufferCapatity(this.readBuffer); } this.readFuture = this.asynchronousSocketChannel.read( this.readBuffer, this, this.readCompletionHandler); } else { throw new IllegalStateException( "Session Or Channel has been closed"); } } }
AsynchronousSocketChannel的read调用与AsynchronousServerSocketChannel的accept调用类似,同样是非阻塞的,返回结果也是一个Future,但是写的结果是整数,表示写入了多少字节,因此read调用返回的是 Future<Integer>,方法的第一个参数是读的缓冲区,操作系统将IO读到数据拷贝到这个缓冲区,第二个参数是传递给 CompletionHandler的attchment,第三个参数就是注册的用于回调的CompletionHandler。这里保存了read的结果Future,这是为了在关闭连接的时候能够主动取消调用,accept也是如此。现在可以看看read的CompletionHandler的实现:
- public final class ReadCompletionHandler implements
- CompletionHandler<Integer, AbstractAioSession> {
- private static final Logger log = LoggerFactory
- .getLogger(ReadCompletionHandler.class);
- protected final AioTCPController controller;
- public ReadCompletionHandler(AioTCPController controller) {
- this.controller = controller;
- }
- @Override
- public void cancelled(AbstractAioSession session) {
- log.warn("Session(" + session.getRemoteSocketAddress()
- + ") read operation was canceled");
- }
- @Override
- public void completed(Integer result, AbstractAioSession session) {
- if (log.isDebugEnabled())
- log.debug("Session(" + session.getRemoteSocketAddress()
- + ") read +" + result + " bytes");
- if (result < 0) {
- session.close();
- return;
- }
- try {
- if (result > 0) {
- session.updateTimeStamp();
- session.getReadBuffer().flip();
- session.decode();
- session.getReadBuffer().compact();
- }
- } finally {
- try {
- session.pendingRead();
- } catch (IOException e) {
- session.onException(e);
- session.close();
- }
- }
- controller.checkSessionTimeout();
- }
- @Override
- public void failed(Throwable exc, AbstractAioSession session) {
- log.error("Session read error", exc);
- session.onException(exc);
- session.close();
- }
- }
public final class ReadCompletionHandler implements CompletionHandler<Integer, AbstractAioSession> { private static final Logger log = LoggerFactory .getLogger(ReadCompletionHandler.class); protected final AioTCPController controller; public ReadCompletionHandler(AioTCPController controller) { this.controller = controller; } @Override public void cancelled(AbstractAioSession session) { log.warn("Session(" + session.getRemoteSocketAddress() + ") read operation was canceled"); } @Override public void completed(Integer result, AbstractAioSession session) { if (log.isDebugEnabled()) log.debug("Session(" + session.getRemoteSocketAddress() + ") read +" + result + " bytes"); if (result < 0) { session.close(); return; } try { if (result > 0) { session.updateTimeStamp(); session.getReadBuffer().flip(); session.decode(); session.getReadBuffer().compact(); } } finally { try { session.pendingRead(); } catch (IOException e) { session.onException(e); session.close(); } } controller.checkSessionTimeout(); } @Override public void failed(Throwable exc, AbstractAioSession session) { log.error("Session read error", exc); session.onException(exc); session.close(); } }
如果IO读失败,会返回失败产生的异常,这种情况下我们就主动关闭连接,通过session.close()方法,这个方法干了两件事情:关闭channel和取消read调用:
- if (null != this.readFuture) {
- this.readFuture.cancel(true);
- }
- this.asynchronousSocketChannel.close();
if (null != this.readFuture) { this.readFuture.cancel(true); } this.asynchronousSocketChannel.close();
在读成功的情况下,我们还需要判断结果result是否小于0,如果小于0就表示对端关闭了,这种情况下我们也主动关闭连接并返回。如果读到一定字节,也就是result大于0的情况下,我们就尝试从读缓冲区中decode出消息,并派发给业务处理器的回调方法,最终通过pendingRead继续发起read调用等待socket的下一次可读。可见,我们并不需要自己去调用channel来进行IO读,而是操作系统帮你直接读到了缓冲区,然后给你一个结果表示读入了多少字节,你处理这个结果即可。而nonblocking IO框架中,是reactor通知用户线程socket可读了,然后用户线程自己去调用read进行实际读操作。这里还有个需要注意的地方,就是decode出来的消息的派发给业务处理器工作最好交给一个线程池来处理,避免阻塞group绑定的线程池。
IO写的操作与此类似,不过通常写的话我们会在session中关联一个缓冲队列来处理,没有完全写入或者等待写入的消息都存放在队列中,队列为空的情况下发起write调用:
- protected void write0(WriteMessage message) {
- boolean needWrite = false;
- synchronized (this.writeQueue) {
- needWrite = this.writeQueue.isEmpty();
- this.writeQueue.offer(message);
- }
- if (needWrite) {
- pendingWrite(message);
- }
- }
- protected final void pendingWrite(WriteMessage message) {
- message = preprocessWriteMessage(message);
- if (!isClosed() && this.asynchronousSocketChannel.isOpen()) {
- this.asynchronousSocketChannel.write(message.getWriteBuffer(),
- this, this.writeCompletionHandler);
- } else {
- throw new IllegalStateException(
- "Session Or Channel has been closed");
- }
- }
protected void write0(WriteMessage message) { boolean needWrite = false; synchronized (this.writeQueue) { needWrite = this.writeQueue.isEmpty(); this.writeQueue.offer(message); } if (needWrite) { pendingWrite(message); } } protected final void pendingWrite(WriteMessage message) { message = preprocessWriteMessage(message); if (!isClosed() && this.asynchronousSocketChannel.isOpen()) { this.asynchronousSocketChannel.write(message.getWriteBuffer(), this, this.writeCompletionHandler); } else { throw new IllegalStateException( "Session Or Channel has been closed"); } }
write调用返回的结果与read一样是一个Future<Integer>,而write的CompletionHandler处理的核心逻辑大概是这样:
- @Override
- public void completed(Integer result, AbstractAioSession session) {
- if (log.isDebugEnabled())
- log.debug("Session(" + session.getRemoteSocketAddress()
- + ") writen " + result + " bytes");
- WriteMessage writeMessage;
- Queue<WriteMessage> writeQueue = session.getWriteQueue();
- synchronized (writeQueue) {
- writeMessage = writeQueue.peek();
- if (writeMessage.getWriteBuffer() == null
- || !writeMessage.getWriteBuffer().hasRemaining()) {
- writeQueue.remove();
- if (writeMessage.getWriteFuture() != null) {
- writeMessage.getWriteFuture().setResult(Boolean.TRUE);
- }
- try {
- session.getHandler().onMessageSent(session,
- writeMessage.getMessage());
- } catch (Exception e) {
- session.onException(e);
- }
- writeMessage = writeQueue.peek();
- }
- }
- if (writeMessage != null) {
- try {
- session.pendingWrite(writeMessage);
- } catch (IOException e) {
- session.onException(e);
- session.close();
- }
- }
- }
@Override public void completed(Integer result, AbstractAioSession session) { if (log.isDebugEnabled()) log.debug("Session(" + session.getRemoteSocketAddress() + ") writen " + result + " bytes"); WriteMessage writeMessage; Queue<WriteMessage> writeQueue = session.getWriteQueue(); synchronized (writeQueue) { writeMessage = writeQueue.peek(); if (writeMessage.getWriteBuffer() == null || !writeMessage.getWriteBuffer().hasRemaining()) { writeQueue.remove(); if (writeMessage.getWriteFuture() != null) { writeMessage.getWriteFuture().setResult(Boolean.TRUE); } try { session.getHandler().onMessageSent(session, writeMessage.getMessage()); } catch (Exception e) { session.onException(e); } writeMessage = writeQueue.peek(); } } if (writeMessage != null) { try { session.pendingWrite(writeMessage); } catch (IOException e) { session.onException(e); session.close(); } } }
compete方法中的result就是实际写入的字节数,然后我们判断消息的缓冲区是否还有剩余,如果没有就将消息从队列中移除,如果队列中还有消息,那么继续发起write调用。
重复一下,这里引用的代码都是yanf4j aio分支中的源码,感兴趣的朋友可以直接check out出来看看: http://yanf4j.googlecode.com/svn/branches/yanf4j-aio。
在引入了aio之后,java对于网络层的支持已经非常完善,该有的都有了,java也已经成为服务器开发的首选语言之一。java的弱项在于对内存的管理上,由于这一切都交给了GC,因此在高性能的网络服务器上还是Cpp的天下。java这种单一堆模型比之erlang的进程内堆模型还是有差距,很难做到高效的垃圾回收和细粒度的内存管理。
这里仅仅是介绍了aio开发的核心流程,对于一个网络框架来说,还需要考虑超时的处理、缓冲buffer的处理、业务层和网络层的切分、可扩展性、性能的可调性以及一定的通用性要求。
发表评论
-
中高级技术人员面试
2012-08-06 14:23 1361struts,spring,hiberate知识点。实际上对于 ... -
关联、聚合、组合的关系
2011-08-19 15:18 1360你和你的心脏之间是co ... -
深入JVM锁机制2-Lock
2011-08-19 11:04 1254分类: JVM 2011-07-28 18:15 92人 ... -
深入JVM锁机制1-synchronized
2011-08-19 11:01 1695分类: JVM 2011-07-28 ... -
CAS ABA问题
2011-08-19 10:55 4668首先要知道什么叫CAS(compare and swap):在 ... -
NIO学习系列:缓冲区内部实现机制
2011-08-17 13:55 994接上一篇NIO学习系列:核心概念及基本读写 ,本 ... -
HTTP协议及报文分析
2011-08-15 21:53 3758一次HTTP操作称为一个 ... -
String、StringBuffer与StringBuilder之间区别
2011-08-15 21:44 1055最近学习到StringBuffer,心中有好些疑问,搜 ... -
Java内存溢出
2011-07-13 11:25 1871内存溢出与数据库锁表的问题,可以说是开发人员的噩梦,一般的 ... -
使用Java NIO编写高性能的服务器
2011-07-12 21:16 1161从JDK 1.4开始,Java的标 ... -
如何中断一个正在运行的线程
2011-07-12 18:03 1737... -
准备问题
2011-07-12 12:06 939你觉得有什么优势 特长 捡干货说你对面试的公司有多了解 怎么看 ... -
NIO学习系列:核心概念及基本读写
2011-07-12 10:20 1129NIO学习系列:缓冲区内部实现机制 http://zh ... -
CAP原理和BASE思想
2011-07-12 10:16 1336分布式领域CAP理论,Co ... -
线程高级---读写锁
2011-07-12 10:15 2111读写锁问题也是比较常见的问题,这是因为现实中充斥着这类问题,而 ... -
Java 中的悲观锁和乐观锁的实现
2011-07-12 10:07 1602锁(locking) 业务逻辑的实现过程中,往往需要保证数 ... -
详细介绍Spring事务管理
2011-07-12 09:47 8513在学习spring事务管理时, ... -
URL与URI区别
2011-07-12 09:46 1213今天在看STRUTS配置的时候,发 ... -
spring原理
2011-07-11 15:57 1017spring原理 spr ... -
Synchronized和java.util.concurrent.locks.Lock的区别
2011-07-11 15:24 5188主要相同点:Lock能完成Synchronized所实现的 ...
相关推荐
在Java编程领域,JDK 7引入了一个重要的更新——NIO2.0,也被称为“New I/O 2.0”或“AIO”(Asynchronous I/O)。这个更新极大地提升了Java处理I/O操作的能力,特别是在文件系统交互和网络通信方面。NIO2.0主要增加...
异步输入/输出(Asynchronous Input/Output,简称AIO),是计算机系统中的一...Java NIO 2.0中的AIO支持为开发高性能、高并发的网络应用提供了便利。在设计AIO框架时,理解并合理运用这些核心概念和组件是至关重要的。
此外,NIO(非阻塞I/O)在Java 2.0中被引入,提供了一种更高效、低延迟的I/O模型,适用于处理大量并发连接。 多线程编程则是Java的一大特色,它允许程序同时执行多个任务,提高了应用程序的效率和响应性。Java中的...
Getty is a high-performance networking framework based entirely on Java NIO encapsulation. 2、getty可在项目中使用,也可以用于帮助你更好的学习java nio Getty can be used in a project or to help you ...
BIO NIO 和 AIO 的区别什么是流 流的分类 节点流和处理流 Java IO 的核心类 File Java IO 流对象 字节流对象InputStream OutputStream 字符流对象Reader Writer 字节流与字符流的转换新潮的 NIO 缓冲区(Buffer)通道...
3. **NIO 2(AIO或NIO 2.0)**:Java 7引入了NIO的增强版,支持异步I/O操作,如AsynchronousServerSocketChannel和AsynchronousSocketChannel,使得开发者可以更方便地实现异步I/O。 在选择合适的Java I/O模型时,...
4. **AIO(Asynchronous I/O)模型或NIO 2.0**:进一步优化了I/O模型,提供了异步非阻塞的I/O操作,使得应用在等待数据准备时可以去做其他事情,提高了系统的吞吐量。 5. **线程池最佳实践**:如何根据实际需求调整...
Java的IO模型主要包括三种:BIO(Blocking I/O)、NIO(Non-blocking I/O)和AIO(Asynchronous I/O)。BIO是最传统的同步阻塞模式,适合连接数量较少且活跃度高的场景;NIO是一种基于通道(Channel)和缓冲区(Buffer)...
4. **JDK7新特性<四> NIO2.0 文件系统** NIO2(非阻塞I/O的第二版)带来了全新的文件系统接口,包括Path API、WatchService API等,提供了异步文件操作和文件事件监听的能力,极大地提升了文件操作的灵活性和性能。...
- **BIO、NIO、AIO**:阻塞I/O、非阻塞I/O、异步I/O。 - **长连接和短连接**:长连接建立后持续使用,短连接每次请求重新建立。 - **HTTP1.0和2.0的区别**:二进制格式、多路复用、头部压缩等。 - **HTTPS的基本...
此外,服务器可能利用了Java的异步I/O模型,如NIO(非阻塞I/O)或者AIO(异步I/O),以提高效率。这些模型允许服务器在等待数据读写时不必阻塞其他任务,从而提高资源利用率和系统性能。 在消息推送方面,服务器...
常见的解决方案包括负载均衡、缓存技术(如Redis和Memcached)、非阻塞I/O(如NIO和AIO)以及线程池管理。此外,采用异步处理和事件驱动模型也能有效提高并发性能。 3. **分布式架构**:分布式架构包括但不限于服务...
- **BIO、NIO、AIO的概念**: - **BIO**:同步阻塞I/O。 - **NIO**:同步非阻塞I/O。 - **AIO**:异步非阻塞I/O。 - **长连接和短连接**: - **长连接**:保持TCP连接不断开。 - **短连接**:每次请求建立新...
为了提高效率和可靠性,还可以考虑使用非阻塞I/O(NIO)或者异步I/O(AIO)进行优化。 总之,Socket编程是实现客户端和服务器之间通信的基础,通过它可以实现文件的高效传输。实际应用中,根据具体需求,可以对上述...
2. **Netty框架**:理解Netty的工作原理,包括BIO、NIO、AIO的区别,以及Netty的Channel、EventLoop、Handler等核心概念。 3. **WebSocket通信**:学习WebSocket协议,实现服务器与客户端的双向通信。 4. **数据库...
7. **互联网高并发解决方案**:面对大量用户请求,需要掌握如何处理高并发,如使用异步非阻塞IO(NIO、AIO)、消息队列(如RabbitMQ、Kafka)进行流量削峰填谷,以及数据库分库分表等策略。 8. **互联网安全架构**...
例如,可能会使用NIO(非阻塞I/O)或AIO(异步I/O)来提升服务器处理能力,同时结合线程池管理,确保系统资源的有效利用。 其次,关于Java部分,这个解决方案可能基于Spring Boot或者Spring Cloud框架,提供微服务...
AmberServer可能采用了常见的服务器架构,如事件驱动模型(如NIO或AIO)或基于工作进程的模型。这些架构设计允许服务器高效地处理I/O操作,减少系统资源的占用,提高服务性能。事件驱动模型利用Java的Selector和...
39. **BIO、NIO、AIO**:BIO是同步阻塞,NIO是同步非阻塞,AIO(又称NIO.2)是异步非阻塞。 40. **数据库索引**:索引是一种数据结构,用于加速查询。B+树是常见的索引实现。 41. **数据库约束**:包括NOT NULL、...
关于Socket的实现方式,Tomcat可以采用BIO(Blocking I/O)、NIO(Non-blocking I/O)或AIO(Asynchronous I/O)等不同的模型,这取决于具体的应用场景和需求。 #### 四、请求分发 考虑到Tomcat能够为多个Web应用...