传统的BIO

我们先使用一个传统的client/server模式来编写了一段两个进程之间通信的代码。ServerSocke负责绑定ip地址、监听相关的端口,Socket负责发起连接操作;这就是一次典型的tcp三次握手。传统的ServerSocket会阻塞在其accept方法上,直到一个客户端发起了连接,然后accept方法返回一个socket,这个socket就负责和我们客户端进行通信。 本例中,书上采用了每返回一个socket(代表每收到一个客户端的连接),就创建并启动一个线程,去做这些具体的通信操作。这样的坏处很明显,当客户端连接增多时,创建大量的线程,这显然是极大的耗费性能的,不满足我们的高并发需求。很容易,我们就想到了一个解决方案——线程池

伪异步I/O

一个看起来可以解决上面问题的方案——线程池,确实在现实中,无脑上线程池是一个能解决很多问题的方案。即我们在服务端放一个线程池,里面有一定数量的线程,来一个客户端的连接,我们就拿出一个线程去和客户端进行通信。这样看起来就已经很美好了,我们下面来分析一下线程池的弊端,或者这么说,线程池并没有解决本质上处理连接时的阻塞问题。

弊端:

1、首先,当对socket输入流进行读取操作时,它会一直阻塞,直到有数据可读或者可用数据读完或者抛异常后才会终止;这意味着如果发送方发送请求消息比较慢、或者网络传输比较慢的时候,读取输入流一方的线程将一直被阻塞;(类似于I/O模型中,需要等待操作系统将数据拷贝至内核缓冲区中)。值得注意的是,输入是针对客户端和服务端双方的,大家都既是输入又是输出。

2、当调用outputstream的write方法时写输出流时,它也将被阻塞,直到所有要发送的字节流被写入完毕,或者发生异常,这里我们需要认识到以前学过的TCP拥塞控制,这就是知识的相关性。 所以,我们的线程池只是治标不治本,并不能完全解决底层的同步阻塞问题。

NIO编程

Non-blocking I/O,NIO是Java提供的一个包,里面封装了一些新的概念,让我们可以直接使用,从而无需关心底层I/O的细节。和它相对应的就是之前的java.io包,