JAVA NIO简解

这篇具有很好参考价值的文章主要介绍了JAVA NIO简解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 了解NIO

JAVA NIO简解

1.1.什么是NIO?

  1. Java nio是Java的一个新的输入输出(NewInput/Output)API,它提供了一些高效的数据处理方式,如缓冲区(buffers)、字符集(charsets)、通道(channels)和选择器(selectors)。
  2. Java NIO可以实现非阻塞式的多路复用输入输出,提高了程序的性能和可扩展性。Java nio是在Java 1.4版本中引入的,后来在Java7中又增加了NIO2,增加了一些新的特性,如文件系统、异步通道和文件监视等。Java NIO的主要类都在java NIO包和其子包中定义。

1.1.NIO和传统IO的区别

    1. JAVA IO是面向流的,JAVA nio是面向缓冲区的。面向流的意思是数据是一个字节一个字节地传输的,面向缓冲区的意思是数据是以块为单位传输的。
    1. JAVA IO是阻塞式的,JAVA nio是非阻塞式的。阻塞式的意思是当一个线程进行读写操作时,它会一直等待直到操作完成,而非阻塞式的意思是当一个线程进行读写操作时,它可以同时进行其他操作,当读写操作完成时会通知线程。
    1. JAVA IO主要有三种类型:字节流、字符流和对象流,JAVA nio主要有三种类型:缓冲区、通道和选择器。缓冲区是用于存储数据的容器,通道是用于连接IO设备的连接,选择器是用于管理多个通道的工具。
    1. JAVA IO主要使用装饰者模式来实现各种功能,JAVA nio主要使用适配器模式来实现各种功能。装饰者模式是通过包装原有的对象来增加新的功能,适配器模式是通过转换原有的对象来适应新的接口。

2.简单体验

ByteBuffer buf = ByteBuffer.allocateDirect(1024) 是在直接内存中的buff,速度更快,零地址转换

2.1.通道 – 读写数据

1.简单读写

//创建一个文件通道
FileChannel fileChannel = FileChannel.open(Paths.get("test.txt"), StandardOpenOption.READ, StandardOpenOption.WRITE);

//创建一个缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);

//从文件通道读取数据到缓冲区
int bytesRead = fileChannel.read(buffer);

//切换缓冲区到读模式
buffer.flip();

//从缓冲区读取数据并打印
while (buffer.hasRemaining()) {
    System.out.print((char) buffer.get());
}

//清空缓冲区
buffer.clear();

//向缓冲区写入数据
buffer.put("Hello, NIO!".getBytes());

//切换缓冲区到写模式
buffer.flip();

//从缓冲区写入数据到文件通道
int bytesWritten = fileChannel.write(buffer);

//关闭文件通道
fileChannel.close();

2.发散聚集

Nio的发散聚集是指使用一个通道分别读写多个缓冲区或者使用多个通道分别读写一个缓冲区的操作。Nio的发散聚集的代码操作如下

//创建一个随机访问文件
RandomAccessFile file = new RandomAccessFile("test.txt", "rw");

//获取文件通道
FileChannel fileChannel = file.getChannel();

//创建两个缓冲区
ByteBuffer buffer1 = ByteBuffer.allocate(10);
ByteBuffer buffer2 = ByteBuffer.allocate(20);

//将两个缓冲区放入一个数组
ByteBuffer[] buffers = {buffer1, buffer2};

//从文件通道读取数据到两个缓冲区,这是发散操作
fileChannel.read(buffers);

//切换缓冲区到读模式
buffer1.flip();
buffer2.flip();

//从两个缓冲区读取数据并打印
while (buffer1.hasRemaining()) {
    System.out.print((char) buffer1.get());
}
System.out.println();
while (buffer2.hasRemaining()) {
    System.out.print((char) buffer2.get());
}
System.out.println();

//清空缓冲区
buffer1.clear();
buffer2.clear();

//向两个缓冲区写入数据
buffer1.put("Hello".getBytes());
buffer2.put("World".getBytes());

//切换缓冲区到写模式
buffer1.flip();
buffer2.flip();

//将两个缓冲区的数据写入到文件通道,这是聚集操作
fileChannel.write(buffers);

//关闭文件通道和随机访问文件
fileChannel.close();
file.close();

3.FileChannel内存映射

FileChannel内存映射文件是指将文件的一部分或全部映射到直接内存中,这样可以提高文件的访问效率,避免了数据在操作系统内存和JVM内存之间的拷贝123。FileChannel内存映射文件的代码操作如下:

//创建一个随机访问文件
RandomAccessFile file = new RandomAccessFile("test.txt", "rw");

//获取文件通道
FileChannel fileChannel = file.getChannel();

//将文件的一部分映射到直接内存中,返回一个MappedByteBuffer对象
MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, file.length());

//读取或修改直接内存中的数据
byte[] data = new byte[mappedByteBuffer.limit()];
mappedByteBuffer.get(data);
System.out.println(new String(data));
mappedByteBuffer.put(0, (byte) 'H');

//关闭文件通道和随机访问文件
fileChannel.close();
file.close();

2.2.管道(Pipe)–线程通信

java NIO
管道是两个线程之间的单向数据连接,有一个source通道和一个sink通道,数据会被写到sink通道,从source通道读取文章来源地址https://www.toymoban.com/news/detail-414673.html

//创建管道
Pipe pipe = Pipe.open();

//获取sink通道
Pipe.SinkChannel sinkChannel = pipe.sink();

//创建缓冲区并写入数据
ByteBuffer buffer = ByteBuffer.allocate(48);
buffer.put("Hello, world!".getBytes());
buffer.flip();

//将缓冲区的数据写入到sink通道
while (buffer.hasRemaining()) {
    sinkChannel.write(buffer);
}

//获取source通道
Pipe.SourceChannel sourceChannel = pipe.source();

//创建缓冲区并从source通道读取数据
buffer.clear();
int bytesRead = sourceChannel.read(buffer);

//打印缓冲区的数据
buffer.flip();
while (buffer.hasRemaining()) {
    System.out.print((char) buffer.get());
}

2.3.网络IO

  1. 服务端代码
//服务端代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class NioServer {
    public static void main(String[] args) throws IOException {
        //创建一个ServerSocketChannel对象
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        //设置为非阻塞模式
        serverSocketChannel.configureBlocking(false);

        //绑定一个端口号
        serverSocketChannel.bind(new InetSocketAddress(8888));

        //创建一个Selector对象
        Selector selector = Selector.open();

        //将ServerSocketChannel注册到Selector上
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        //在一个循环中调用Selector的select方法
        while (true) {
            //获取已经就绪的通道集合
            int readyChannels = selector.select();
            if (readyChannels == 0) continue;

            //遍历就绪的通道集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                //获取当前的SelectionKey
                SelectionKey selectionKey = iterator.next();

                //根据不同的事件类型进行处理
                if (selectionKey.isAcceptable()) {
                    //如果是OP_ACCEPT事件
                    //获取对应的SocketChannel对象
                    SocketChannel socketChannel = serverSocketChannel.accept();

                    //设置为非阻塞模式
                    socketChannel.configureBlocking(false);

                    //注册到Selector上,关注OP_READ事件
                    socketChannel.register(selector, SelectionKey.OP_READ);
                } else if (selectionKey.isReadable()) {
                    //如果是OP_READ事件
                    //获取对应的SocketChannel对象
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();

                    //创建一个ByteBuffer对象,用于存储读取到的数据
                    ByteBuffer buffer = ByteBuffer.allocate(1024);

                    //从通道中读取数据到缓冲区
                    int len = socketChannel.read(buffer);

                    //判断是否读到了数据
                    if (len > 0) {
                        //切换缓冲区到读模式
                        buffer.flip();

                        //打印读取到的数据
                        System.out.println("Server received: " + new String(buffer.array(), 0, len));
                    }
                } else if (selectionKey.isWritable()) {
                    //如果是OP_WRITE事件
                    //获取对应的SocketChannel对象
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();

                    //创建一个ByteBuffer对象,用于存储要写入的数据
                    ByteBuffer buffer = ByteBuffer.wrap("Hello, client".getBytes());

                    //将缓冲区的数据写入到通道中
                    socketChannel.write(buffer);
                }

                //移除当前的SelectionKey,避免重复处理
                iterator.remove();
            }
        }
    }
}
  1. 客户端
//客户端代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class NioClient {
    public static void main(String[] args) throws IOException {
        //创建一个SocketChannel对象
        SocketChannel socketChannel = SocketChannel.open();

        //设置为非阻塞模式
        socketChannel.configureBlocking(false);

        //连接到服务器的地址和端口号
        socketChannel.connect(new InetSocketAddress("127.0.0.1", 8888));

        //创建一个Selector对象
        Selector selector = Selector.open();

        //注册到Selector上,关注OP_CONNECT事件
        socketChannel.register(selector, SelectionKey.OP_CONNECT);

        //在一个循环中调用Selector的select方法
        while (true) {
            //获取已经就绪的通道集合
            int readyChannels = selector.select();
            if (readyChannels == 0) continue;

            //遍历就绪的通道集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                //获取当前的SelectionKey
                SelectionKey selectionKey = iterator.next();

                //根据不同的事件类型进行处理
                if (selectionKey.isConnectable()) {
                    //如果是OP_CONNECT事件
                    //获取对应的SocketChannel对象
                    SocketChannel channel = (SocketChannel) selectionKey.channel();

                    //如果连接已经完成
                    if (channel.finishConnect()) {
                        //注册到Selector上,关注OP_WRITE事件
                        channel.register(selector, SelectionKey.OP_WRITE);
                    }
                } else if (selectionKey.isWritable()) {
                    //如果是OP_WRITE事件
                    //获取对应的SocketChannel对象
                    SocketChannel channel = (SocketChannel) selectionKey.channel();

                    //创建一个ByteBuffer对象,用于存储要写入的数据
                    ByteBuffer buffer = ByteBuffer.wrap("Hello, server".getBytes());

                    //将缓冲区的数据写入到通道中
                    channel.write(buffer);

                    //注册到Selector上,关注OP_READ事件
                    channel.register(selector, SelectionKey.OP_READ);
                } else if (selectionKey.isReadable()) {
                    //如果是OP_READ事件
                    //获取对应的SocketChannel对象
                    SocketChannel channel = (SocketChannel) selectionKey.channel();

                    //创建一个ByteBuffer对象,用于存储读取到的数据
                    ByteBuffer buffer = ByteBuffer.allocate(1024);

                    //从通道中读取数据到缓冲区
                    int len = channel.read(buffer);

                    //判断是否读到了数据
                    if (len > 0) {
                        //切换缓冲区到读模式
                        buffer.flip();

                        //打印读取到的数据
                        System.out.println("Client received: " + new String(buffer.array(), 0, len));
                    }
                }

                //移除当前的SelectionKey,避免重复处理
                iterator.remove();
            }
        }
    }
}

到了这里,关于JAVA NIO简解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Web3】什么是Web3?一个新的去中心化网络,或是最新的营销流行语

    Web3已成为一种将区块链、智能合约和去中心化应用程序结合在一起的尝试,但其真正的功效难以确定。 Web3,如Web3基金会设想的那样,将是一个公共互联网,数据和内容被注册在块链上,在对等分布式网络上进行令牌化或管理和访问。 Web3有望成为一个去中心化的、不可变的

    2024年01月21日
    浏览(50)
  • 浏览器输入一个URL之后发生了什么?

    URL解析 DNS解析 TCP连接 TSL连接 HTTP请求 TCP挥手 接收并解析响应 主要分为: 协议,eg http,https 域名或者ip地址,eg www.baidu.com 域名相对于ip地址来说,更方便人们记忆,但是实际的网络传输中使用的是ip地址 端口号,不同的协议对应不同的端口号,一般可以不写,eg http是80,h

    2024年02月11日
    浏览(73)
  • 深入了解:Java中获取 List中最后一个元素

    在Java编程中,我们经常会使用List来存储一组元素。有时候,我们需要获取List中的最后一个元素。本文将介绍几种获取List中最后一个元素的方法。 List接口提供了一个get()方法,可以通过索引来获取List中的元素。由于List的索引是从0开始的,所以最后一个元素的索引是List的大

    2024年02月07日
    浏览(53)
  • 写一个简单的Java的Gui文本输入窗口,JFrame的简单使用

             JFrame 是指一个计算机语言-java的GUI程序的基本思路是以JFrame为基础,它是屏幕上window的对象,能够最大化、最小化、关闭。 Swing的三个基本构造块:标签、按钮和文本字段;但是需要个地方安放它们,并希望用户知道如何处理它们。JFrame 类就是解决这个问题的—

    2024年01月22日
    浏览(39)
  • Java开发 - 带你了解集群间的相互调用,你还在等什么?

    目录 前言 导读 项目准备 集群准备 父工程引入子项目 服务调用方HelloService准备 pom文件 yml文件 Controller文件 服务提供方HelloWorld准备  pom文件 yml文件 Controller文件  运行此两个工程  hello_world组集群 集群调用测试 RestTemplate换成Dubbo行不行,怎么换 两个pom文件引入依赖  两个启

    2024年02月09日
    浏览(42)
  • BIO、NIO、AIO 有什么区别?

    Java 中的I/O模型主要分为三类:BIO(Blocking I/O)、NIO(New I/O)和AIO(Asynchronous I/O)。它们在处理I/O操作时有着不同的工作方式和特点。 BIO是传统的I/O模型,也称为同步I/O。在BIO中,每个I/O操作都会阻塞线程,直到数据准备好或者操作完成。这意味着一个线程只能处理一个连

    2024年01月16日
    浏览(46)
  • BIO、NIO、AIO 有什么区别

    在Java中,BIO(Blocking I/O)、NIO(Non-blocking I/O)和AIO(Asynchronous I/O)都是用于处理I/O(输入/输出)操作的不同方式。它们在处理I/O时具有不同的特点和适用场景。 BIO(Blocking I/O): 阻塞式I/O模型,是Java最传统的I/O模型。 在BIO中,每个I/O操作都会阻塞当前线程,直到操作完

    2024年02月13日
    浏览(35)
  • 学Java线程,你不知道什么是AQS?一文带你了解Java多线程同步的灵魂

    关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。 我们继续总结学习 Java基础知识 ,温故知新。 CLH(Craig, Landin, and Hagersten locks)是一种自旋锁,能确保无饥饿性,提

    2024年02月16日
    浏览(47)
  • Java——它要求用户输入一个整数(实际上是一个字符串),然后计算该整数的平方值,并将结果输出。

    这是一个Java程序,它要求用户输入一个整数(实际上是一个字符串),然后计算该整数的平方值,并将结果输出。程序的基本流程如下: 首先,声明并初始化变量data和result,它们的初始值都为0。 然后,输出提示信息,要求用户输入一个整数。 接下来,使用BufferedReader类从

    2024年02月11日
    浏览(44)
  • Java NIO (三)NIO Channel类

            前面提到,Java NIO中一个socket连接使用一个Channel来表示。从更广泛的层面来说,一个通道可以表示一个底层的文件描述符,例如硬件设备、文件、网络连接等。然而,远不止如此,Java NIO的通道可以更加细化。例如,不同的网络传输协议,在Java中都有不同的NIO Chann

    2024年01月18日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包