java NIO基础

news/2024/7/9 18:19:20 标签: java, epoll, 运维

java-io-分类">Java I/O 分类

  • 磁盘操作:File
  • 字节操作:InputStream 和 OutputStream
  • 字符操作: Writer 和 Reader
  • 对象操作:Serializable
  • 网络操作:Socket
  • 新的输入/输出:NIO

来源-极客时间

NIO

(1)通道(Channel)

通道 Channel 是对原 I/O 包中的流的模拟,Channel 本身不能直接访问数据,Channel 只能与Buffer 进行交互。

通道与流的不同之处在于,流只能在一个方向上移动(一个流必须是 InputStream 或者 OutputStream 的子类),而通道是双向的,可以用于读、写或者同时用于读写。

通道包括以下类型:

  • FileChannel:从文件中读写数据;
  • DatagramChannel:通过 UDP 读写网络中数据;
  • SocketChannel:通过 TCP 读写网络中数据;
  • ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。
(2)缓冲区(Buffer)

发送给一个通道的所有数据都必须首先放到缓冲区中,同样地,从通道中读取的任何数据都要先读到缓冲区中。也就是说,不会直接对通道进行读写数据,而是要先经过缓冲区。

缓冲区实质上是一个数组,但它不仅仅是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。

除了布尔类型,所有原始数据类型都有相应的 Buffer 实现

直接与非直接内存
  • 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中。适用于并发连接数少于1000,I/O操作较少

  • 直接字节缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。适用于数据量比较大,生命周期比较长

  • allocateDirect()方法返回的DirectByteBuffer就是与底层存储空间关联的缓冲区,它通过Native代码操作非JVM堆的内存空间,每次创建或者释放的时候都调用System.gc()。注意,使用DirectByteBuffer时可能会引起JVM内存泄漏的问题。

  • 字节缓冲区是直接缓冲区还是非直接缓冲区通过调用其 isDirect() 方法确定。

(3)选择器(Selector)

NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。
Selector 通过轮询的方式去监听多个通道 Channel 上的事件,从而让一个线程就可以处理多个事件。这样,一个单独的线程可以管理多个Channel,从而管理多个网络连接。

Linux 上依赖于 epoll实现-源码

NIO使用实例

java">public class NIOTest {

    public static void main(String[] args) throws IOException {
        //创建选择器
        Selector selector = Selector.open();
        //将通道注册到选择器上
        ServerSocketChannel ssChannel = ServerSocketChannel.open();
        ssChannel.configureBlocking(false);
        ssChannel.register(selector, SelectionKey.OP_ACCEPT);

        ServerSocket serverSocket = ssChannel.socket();
        InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8888);
        serverSocket.bind(address);

        while (true) {
            //一次 select()调用不能处理完所有的事件,并且服务器端有可能需要一直监听事件
            //因此服务器端处理事件的代码一般会放在一个死循环内。
            selector.select();
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> keyIterator = keys.iterator();

            while (keyIterator.hasNext()) {
                SelectionKey key = keyIterator.next();
                if (key.isAcceptable()) {
                    ServerSocketChannel ssChannel1 = (ServerSocketChannel) key.channel();
                    // 服务器会为每个新连接创建一个 SocketChannel
                    SocketChannel sChannel = ssChannel1.accept();
                    sChannel.configureBlocking(false);
                    // 这个新连接主要用于从客户端读取数据
                    sChannel.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    SocketChannel sChannel = (SocketChannel) key.channel();
                    System.out.println(readDataFromSocketChannel(sChannel));
                    sChannel.close();
                }
                keyIterator.remove();
            }
        }
    }

    private static String readDataFromSocketChannel(SocketChannel sChannel) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        StringBuilder data = new StringBuilder();

        while (true) {
            buffer.clear();
            int n = sChannel.read(buffer);
            if (n == -1) {
                break;
            }
            buffer.flip();
            int limit = buffer.limit();
            char[] dst = new char[limit];
            for (int i = 0; i < limit; i++) {
                dst[i] = (char) buffer.get(i);
            }
            data.append(dst);
            buffer.clear();
        }
        return data.toString();
    }
}
java">public class NIOClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 8888);
        OutputStream out = socket.getOutputStream();
        String s = "Hello world";
        out.write(s.getBytes());
        out.close();
    }
}

转载于:https://www.cnblogs.com/flyuz/p/11408437.html


http://www.niftyadmin.cn/n/1802545.html

相关文章

时间差计算

现在是 &#xff1a;2004-03-26 13&#xff1a;31&#xff1a;40 过去是&#xff1a;2004-01-02 11&#xff1a;30&#xff1a;24 我现在要获得两个日期差&#xff0c;差的形式为&#xff1a;XX天XX小时XX分XX秒 这前后时间可能是机器生成的&#xff0c;也可能是人工输入的&…

System.Web.Optimization 找不到引用,教你如何解决?

在程序中偶尔会遇到这种错误&#xff1a; 编译错误 说明: 在编译向该请求提供服务所需资源的过程中出现错误。请检查下列特定错误详细信息并适当地修改源代码。 编译器错误消息: CS0234: 命名空间“System.Web”中不存在类型或命名空间名称“Optimization”(是否缺少…

bzoj2716 2716: [Violet 3]天使玩偶

2716: [Violet 3]天使玩偶 Time Limit: 80 Sec Memory Limit: 128 MBSubmit: 2943 Solved: 1292[Submit][Status][Discuss]Description Input Output 同&#xff1a; 2648 &#xff0c;需要插入的kd树。 1 #include<bits/stdc.h>2 using namespace std; 3 int const …

2019/8/27 校内模拟赛 考试报告

A.挑战(challenge.cpp) 首先令\(x_imax(a_i-k,0)\),即破坏第\(i\)个防御区域的代价. 设\(dp_i\)表示从\(1...i\)需要的最小代价,有状态转移方程:\(dp_imin(dp_j)x_i\),其中\(i-L\le j\le i-1\). 初始化边界\(dp_00,dp_{1...n1}inf\).动态规划求出\(dp_{n1}\)即可. 时间复杂度\(…

# pycharm新建项目后运行按钮为灰色

pycharm新建项目后运行按钮为灰色 第一次运行需要先为项目创建解释器&#xff0c;第一次可以对项目右键选中Run或者CtrlShiftF10自动为项目创建解释器。或者手动Run->Edit Configurations-> ->新建python指定Scrip path为当前xxx.py的路径转载于:https://www.cnblogs…

高可用Redis:Redis Cluster

转&#xff08;https://www.cnblogs.com/renpingsheng/p/9862485.html&#xff09; Redis Cluster是Redis官方提供的Redis集群功能 1.为什么要实现Redis Cluster 1.主从复制不能实现高可用 2.随着公司发展&#xff0c;用户数量增多&#xff0c;并发越来越多&#xff0c;业务需要…

公路、市场、铁路施工特级企业 ---- 最新情况

公路、市场、铁路施工特级企业 ---- 最新情况&#xff1a; 1、北京建工路桥集团有限公司 https://mp.weixin.qq.com/s/eNU8QBmbzhw1GZ6vu5NY2A 转载于:https://www.cnblogs.com/hopesun/p/11422548.html

RPA 机器人自动化

RPA 机器人自动化&#xff1a; 1、UiBot &#xff1a;https://www.uibot.com.cn/ 2、UiPath、 3、估值26亿美元的美国独角兽Automation Anywhere、 4、市值16亿英镑左右的英国上市公司Blueprism等。 转载于:https://www.cnblogs.com/hopesun/p/11423251.html