服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 一文带你你搞懂Java的3种IO模型

一文带你你搞懂Java的3种IO模型

2023-05-12 01:07未知服务器之家 Java教程

目录 Java BIO Java NIO Java AIO 小结 在Java中,一共有三种IO模型,分别是 阻塞IO(BIO) 、 非阻塞IO(NIO) 和 异步IO(AIO) 。 Java BIO Java BIO 就是Java的传统IO模型,对应了操作系统IO模型里的阻塞IO。 Java BIO 相关的实现都位于 java.io 包下,其通信

目录
  • Java BIO
  • Java NIO
  • Java AIO
  • 小结

在Java中,一共有三种IO模型,分别是阻塞IO(BIO)非阻塞IO(NIO)异步IO(AIO)

一文带你你搞懂Java的3种IO模型

  • BioClient
/**
 * @Author 三分恶
 * @Date 2023/4/30
 * @Description BIO客户端
 */
public class BioClient {

    public static void main(String[] args) throws IOException {
        List<String> names= Arrays.asList("帅哥","靓仔","坤坤");
        //通过循环创建多个多个client
        for (String name:names){
            //创建socket并根据IP地址与端口连接服务端
            Socket socket=new Socket("127.0.0.1",8888);
            System.out.println("===========BIO客户端启动================");
            //从socket中获取字节输出流
            OutputStream outputStream=socket.getOutputStream();
            //通过输出流向服务端传递信息
            String hello="你好,"+name+"!";
            outputStream.write(hello.getBytes());
            //清空流,关闭socket输出
            outputStream.flush();
            socket.shutdownOutput();

            //从socket中获取字节输入流
            InputStream inputStream=socket.getInputStream();
            BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
            //读取服务端消息
            String msg;
            while((msg=bufferedReader.readLine())!=null){
                System.out.println("收到服务端消息:"+msg);
            }
            inputStream.close();
            outputStream.close();
            socket.close();
        }
    }
}
  • 先启动BioServer,再启动BioClient,运行结果

 ===========BIO服务端启动================
收到客户端消息:你好,帅哥!
收到客户端消息:你好,靓仔!
收到客户端消息:你好,坤坤!

 ===========BIO客户端启动================
收到服务端消息:你好,吊毛!
===========BIO客户端启动================
收到服务端消息:你好,吊毛!
===========BIO客户端启动================
收到服务端消息:你好,吊毛!

在上述Java-BIO的通信过程中,如果客户端一直没有发送消息过来,服务端则会一直等待下去,从而服务端陷入阻塞状态。同理,由于客户端也一直在等待服务端的消息,如果服务端一直未响应消息回来,客户端也会陷入阻塞状态。

BioServer定义了一个类BioServerThread,继承了Thread类,run方法里主要是通过socket和流来读取客户端的消息,以及发送消息给客户端,每处理一个客户端的Socket连接,就得新建一个线程。

同时,IO读写操作也是阻塞的,如果客户端一直没有发送消息过来,线程就会进入阻塞状态,一直等待下去。

BioClient里,循环创建Socket,向服务端收发消息,客户端的读写也是阻塞的。

在这个Demo里就体现了BIO的两个特点:

  • 一个客户端连接对应一个处理线程
  • 读写操作都是阻塞的

一文带你你搞懂Java的3种IO模型

  • NioClient
public class NioClient {

    public static void main(String[] args) throws IOException {
        // 创建SocketChannel并指定ip地址和端口号
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8888));
        System.out.println("==============NIO客户端启动================");
        // 非阻塞模式
        socketChannel.configureBlocking(false);
        String hello="你好,靓仔!";
        ByteBuffer buffer = ByteBuffer.wrap(hello.getBytes());
        // 向通道中写入数据
        socketChannel.write(buffer);
        System.out.println("发送消息:" + hello);
        buffer.clear();
        // 将channel注册到Selector并监听READ事件
        socketChannel.register(Selector.open(), SelectionKey.OP_READ, buffer);
        while (true) {
            // 读取服务端数据
            if (socketChannel.read(buffer) > 0) {
                buffer.flip();
                String msg = new String(buffer.array(), 0, buffer.limit());
                System.out.println("收到服务端消息:" + msg);
                break;
            }
        }
        // 关闭输入流
        socketChannel.shutdownInput();
        // 关闭SocketChannel连接
        socketChannel.close();
    }
}
  • 先运行NioServer,再运行NioClient,运行结果:

 ===========NIO服务端启动============
===========NIO服务端超时等待============
===========NIO服务端超时等待============
成功连接客户端
收到客户端消息:你好,靓仔!
向客户端发送消息:你好啊!

 ==============NIO客户端启动================
发送消息:你好,靓仔!
收到服务端消息:你好啊!

我们在这个案例里实现了一个比较简单的Java NIO 客户端服务端通信,里面有两个小的点需要注意,注册到选择器上的通道都必须要为非阻塞模型,同时通过缓冲区传输数据时,必须要调用flip()方法切换为读取模式。

一文带你你搞懂Java的3种IO模型

  • AioClient
/**
 * @Author 三分恶
 * @Date 2023/5/1
 * @Description AIO客户端
 */
public class AioClient {

    public static void main(String[] args) throws Exception {
        // 创建异步Socket通道
        AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
        // 异步连接服务器
        client.connect(new InetSocketAddress("127.0.0.1", 8888), null, new CompletionHandler<Void, Object>() {
            // 创建ByteBuffer
            final ByteBuffer buffer = ByteBuffer.wrap(("你好,靓仔!").getBytes());

            @Override
            public void completed(Void result, Object attachment) {
                // 异步发送消息给服务器
                client.write(buffer, null, new CompletionHandler<Integer, Object>() {
                    // 创建ByteBuffer
                    final ByteBuffer readBuffer = ByteBuffer.allocate(1024);

                    @Override
                    public void completed(Integer result, Object attachment) {
                        readBuffer.clear();
                        // 异步读取服务器发送的消息
                        client.read(readBuffer, null, new CompletionHandler<Integer, Object>() {
                            @Override
                            public void completed(Integer result, Object attachment) {
                                readBuffer.flip();
                                String msg = new String(readBuffer.array(), 0, result);
                                System.out.println("收到服务端消息:" + msg);
                            }

                            @Override
                            public void failed(Throwable exc, Object attachment) {
                                exc.printStackTrace();
                                try {
                                    client.close();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }

                    @Override
                    public void failed(Throwable exc, Object attachment) {
                        exc.printStackTrace();
                        try {
                            client.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }

            @Override
            public void failed(Throwable exc, Object attachment) {
                exc.printStackTrace();
                try {
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        // 等待连接处理完毕
        Thread.sleep(1000);
        // 关闭输入流和Socket通道
        client.shutdownInput();
        client.close();
    }
}
  • 看下运行结果

 =============AIO服务端启动=========
客户端连接成功
收到客户端消息:你好,靓仔!

 收到服务端消息:你好啊!

可以看到,所有的操作都是异步进行,通过completed接收异步回调,通过failed接收错误回调。

而且我们发现,相较于之前的NIO而言,AIO其中少了Selector选择器这个核心组件,选择器在NIO中充当了协调者的角色。

但在Java-AIO中,类似的角色直接由操作系统担当,而且不是采用轮询的方式监听IO事件,而是采用一种类似于“订阅-通知”的模式。

一文带你你搞懂Java的3种IO模型

我们也发现,虽然Java-NIOJava-AIO,在性能上比Java-BIO要强很多,但是可以看到,写法上一个比一个难搞,不过好在基本也没人直接用Java-NIOJava-AIO,如果要进行网络通信,一般都会采用Netty,它对原生的Java-NIO进行了封装优化,接下来,我们会继续走近Netty,敬请期待。

以上就是一文带你你搞懂Java的3种IO模型的详细内容,更多关于Java IO模型的资料请关注其它相关文章!

原文地址:https://juejin.cn/post/7231594699092492349

延伸 · 阅读

精彩推荐