点击上方 "程序员小乐"关注, 星标或置顶一起成长
第一时间与你相约
每日英文
We all have a past. It’s how you deal with it.
每个人都有过去,只是取决于你怎么去处理。
每日掏心话
人不都是这样吗,安慰别人的时候头头是道,自己遇上点过不去的坎立马无法自拔,道理都懂,只是情绪作祟,故事太撩人。
来自:JavaDoop | 责编:乐乐
链接:javadoop.com/post/nio-and-aio
程序员小乐(ID:study_tech)第 705 次推文 图片来自网络
往日回顾:千万别惹程序员,否则会在代码注释里,告诉这家公司有多坑!、ef+Npoi导出百万行excel之踩坑记
正文
上一篇文章介绍了 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