上一篇文章先容了 Java NIO 中 Buffer、Channel 和 Selector 的根基操纵,主要是一些接口操纵,较量简朴。
本文将先容非阻塞 IO 和异步 IO,也就是各人耳熟能详的 NIO 和 AIO。许多初学者大概分不清楚异步和非阻塞的区别,只是在各类场所能听到异步非阻塞这个词。
本文会先先容并演示阻塞模式,然后引入非阻塞模式来对阻塞模式举办优化,最后再先容 JDK7 引入的异步 IO,由于网上关于异步 IO 的先容相对较少,所以这部门内容我会先容得详细一些。
但愿看完本文,读者可以对非阻塞 IO 和异步 IO 的迷雾看得更清晰些,可能为初学者解开一丝丝迷惑也是好的。
NIO,JDK1.4,New IO,Non-Blocking IO
NIO.2,JDK7,More New IO,Asynchronous IO,严格地说 NIO.2 不只仅引入了 AIO
阻塞模式 IO
我们已经先容过利用 Java NIO 包构成一个简朴的客户端-处事端网络通讯所需要的 ServerSocketChannel、SocketChannel 和 Buffer,我们这里整合一下它们,给出一个完整的可运行的例子:
public class Server {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 监听 8080 端口进来的 TCP 链接
serverSocketChannel.socket().bind(new InetSocketAddress(8080));
while (true) {
// 这里会阻塞,直到有一个请求的毗连进来
SocketChannel socketChannel = serverSocketChannel.accept();
// 开启一个新的线程来处理惩罚这个请求,然后在 while 轮回中继承监听 8080 端口
SocketHandler handler = new SocketHandler(socketChannel);
new Thread(handler).start();
}
}
}
这里看一下新的线程需要做什么,SocketHandler:
public class SocketHandler implements Runnable {
private SocketChannel socketChannel;
public SocketHandler(SocketChannel socketChannel) {
this.socketChannel = socketChannel;
}
@Override
public void run() {
ByteBuffer buffer = ByteBuffer.allocate(1024);
try {
// 将请求数据读入 Buffer 中
int num;
while ((num = socketChannel.read(buffer)) > 0) {
// 读取 Buffer 内容之前先 flip 一下
buffer.flip();
// 提取 Buffer 中的数据
byte[] bytes = new byte[num];
buffer.get(bytes);
String re = new String(bytes, "UTF-8");
System.out.println("收到请求:" + re);
// 回应客户端
ByteBuffer writeBuffer = ByteBuffer.wrap(("我已经收到你的请求,你的请求内容是:" + re).getBytes());
socketChannel.write(writeBuffer);
buffer.flip();
}
} catch (IOException e) {
IOUtils.closeQuietly(socketChannel);
}
}
}
最后,贴一下客户端 SocketChannel 的利用,客户端较量简朴:
public class SocketChannelTest {
public static void main(String[] args) throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("localhost", 8080));
// 发送请求
ByteBuffer buffer = ByteBuffer.wrap("1234567890".getBytes());
socketChannel.write(buffer);
// 读取响应
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int num;
if ((num = socketChannel.read(readBuffer)) > 0) {
readBuffer.flip();
byte[] re = new byte[num];
readBuffer.get(re);
String result = new String(re, "UTF-8");
System.out.println("返回值: " + result);
}
}
}
上面先容的阻塞模式的代码应该很好领略:来一个新的毗连,我们就新开一个线程来处理惩罚这个毗连,之后的操纵全部由谁人线程来完成。
那么,这个模式下的机能瓶颈在那边呢?
非阻塞 IO
说完了阻塞模式的利用及其缺点今后,我们这里就可以先容非阻塞 IO 了。