Java NIO

I/O简介 

  I/O问题可以说是当今web应用中所面临的的主要问题之一,大部分的web应用系统的瓶颈都是I/O瓶颈。这个系列主要介绍JAVA的I/O类库基本架构、磁盘I/O工作机制、网络I/O工作机制以及NIO的工作方式。

BIO(Block IO)和Nio(Non-Block IO)的对比

IO模式BIONIO
方式从磁盘到磁盘从缓存到磁盘
通信缓存(多级复用)
处理阻塞非阻塞(Reactor)
触发选择器轮询机制

 

从1.4版本开始JAVA引入了NIO,用来提升I/O性能。I/O操作类在包java.io下,大概有将近80个类

这些类可以分为如下四组:

  基于字节操作的I/O接口:InputStream和OutputStream

  基于字符操作的I/O接口:Reader和Writer

  基于磁盘操作的I/O接口:File

  基于网络操作的I/O接口:Socket

前两组是传输数据的格式,后两组是传输数据的方式

核心组件

核心组件定义作用特点使用

通道

(Channel)

NIO数据的源头/目的地

(Buffer的唯一接口)

向缓存提供数据

读取换区的数据

双向读写,异步读写

数据来源/流向 总是Buffer

根据来源区别:

FileChannel:从文件

DataChannel:从UDP网络数据

SocketChannel:

ServerSocketChannel

缓存

(Buffer)

NIO数据读/写中转地

(一块完整的内存块)

数据缓存适用于处布尔外基本数据类型

7种基本数据类型

 

选择器

(Selector)

异步IO核心类实现异步非阻塞IO

使用一个Selector线程检测1个/多个

通道channel上的事件,给予事件驱动

分发不需要为每个channel去分配一个线程

1、创建Selector对象

2、箱Slector注册通道Channel

2、调用Selector类中select()方法

一、Buffer缓存区

1) Buffer介绍: 缓冲区,本质就是一个数组,但是它是特殊的数组,缓冲区对象内置了一些机制,能够追踪和记录缓冲区的状态变化情况,如果我们使用get方法从   缓冲区中获取数据或者用put方法吧数据写入缓冲区,都会引起缓冲区的状态变化
在缓冲区中,最重要的属性是如下三个,他们一起合作完成了对缓冲区内容状态的变化跟踪
1)position:指定了下一个将要被写入或者读取的元素索引,它的值由get()/put() 方法自动更新,在新创建一个Buffer对象时,position被初始化为0
2)limit:操作缓冲区的可操作空间和可操作范围,指定还有多少数据需要去除,或者还有多少空间可以放入数据
3)capacity:指定了可以存储在缓冲区中的最大数据容量,实际上,它指定了底层数组的大小,或者至少是指定了准许我们使用的底层数组的容量。

以上三个属性值之间有一些相对的大小的关系:0<=position<=limit<=capacity

package com.Allen.buffer;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class testBufferDemo01 {
    public static void main(String[] args) throws IOException {
        String fileURL="F://a.txt";
        FileInputStream fis=new FileInputStream(fileURL);
        //获取通路
        FileChannel channel=fis.getChannel();
        //定义缓冲区大小
        ByteBuffer buffer=ByteBuffer.allocate(10);
        output("init", buffer);
        //先读
        channel.read(buffer);
        output("read", buffer);
        buffer.flip();
        output("flip", buffer);        
        while (buffer.hasRemaining()) {
            byte b=buffer.get();
        }
        output("get", buffer);
        buffer.clear();
        output("clear", buffer);
        fis.close();
    }
    
    public static void output(String string,ByteBuffer buffer){
        System.out.println(string);
        System.out.println(buffer.capacity()+":"+buffer.position()+":"+buffer.limit());
    }
}

二、Channel(通路)

任何时候读取数据,都不是直接从通道中读取,而是从通道读取到缓冲区,所以使用NIO读取数据可以分成下面三个步骤
1)从FileInputStream获取Channel
2)创建Buffer
3)将数据从Channel 读取到Buffer中

package com.allen.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class testNio {
    public static void main(String[] args) throws IOException {
        String oldFileUrl="E://1.txt";
        String newFileUrl="E://2.txt";
        FileInputStream fis=new FileInputStream(oldFileUrl);
     //1、获取Channel FileChannel inChannel
=fis.getChannel();
     //2、创建Buffer ByteBuffer bf
=ByteBuffer.allocate(1024); FileOutputStream fos=new FileOutputStream(newFileUrl); FileChannel outChannel=fos.getChannel(); while(true){ int eof=inChannel.read(bf); if(eof==-1){ break; }else{ bf.flip();
     //3、把数据写入缓存 outChannel.write(bf); bf.clear(); } } inChannel.close(); fis.close(); outChannel.close(); fos.close(); } }

三、Selector(选择器)

  Selector 一般称 为选择器 ,也即多路复用器 。它是Java NIO核心组件中的一个,用于检查一个或多个NIO Channel(通道)的状态是否处于可读、可写。如此可以实现单线程管理多个channels,也就是可以管理多个网络链接。
   使用Selector的好处: 使用更少的线程来就可以来处理通道了, 相比使用多个线程,避免了线程上下文切换带来的开销。
 // 1. 创建Selector对象   
 Selector sel = Selector.open();

 // 2. 向Selector对象绑定通道   
 // a. 创建可选择通道,并配置为非阻塞模式   
 ServerSocketChannel server = ServerSocketChannel.open();   
 server.configureBlocking(false);   
 
 // b. 绑定通道到指定端口   
 ServerSocket socket = server.socket();   
 InetSocketAddress address = new InetSocketAddress(port);   
 socket.bind(address);   
 
 // c. 向Selector中注册感兴趣的事件   
 server.register(sel, SelectionKey.OP_ACCEPT);    
 return sel;

// 3. 处理事件
try {    
    while(true) { 
        // 该调用会阻塞,直到至少有一个事件就绪、准备发生 
        selector.select(); 
        // 一旦上述方法返回,线程就可以处理这些事件
        Set<SelectionKey> keys = selector.selectedKeys(); 
        Iterator<SelectionKey> iter = keys.iterator(); 
        while (iter.hasNext()) { 
            SelectionKey key = (SelectionKey) iter.next(); 
            iter.remove(); 
            process(key); 
        }    
    }    
} catch (IOException e) {    
    e.printStackTrace();   
}

总结nio工作原理

1)由一个专门的线程去处理所有的io事件并且负责分发
2)事件驱动机制,时间到的时候触发,而不是同步地去监听事件
3)线程通信,线程之间通过wait,notify等方式通信,保证每次上下文切换都是有意义的,减少无畏的线程切换。

转载于:https://www.cnblogs.com/Chi-Sophia/p/10191784.html

03-15
### Java NIO 教程与文档 Java NIO 是一种基于缓冲区和通道的 I/O 处理方式,相较于传统的 Java IO 更高效且适合处理大规模数据传输。以下是关于 Java NIO 的一些核心概念及其学习资源。 #### 1. **核心组件** Java NIO 主要由以下几个部分组成: - **Buffer**: 数据容器,用于存储不同类型的原始数据[^4]。 - **Channel**: 类似于流的概念,但支持双向读写操作。 - **Selector**: 支持多路复用机制,允许单线程管理多个 Channel。 这些组件共同构成了高效的非阻塞 I/O 模型,适用于网络编程和文件操作场景。 #### 2. **官方文档** Oracle 官方文档提供了详尽的 Java NIONIO.2 API 描述以及使用示例。可以通过访问 Oracle 官网并搜索 "Java SE documentation" 来获取最新的官方文档[^3]。 #### 3. **教程推荐** Baeldung 网站上的教程涵盖了 Java NIO 的基本原理及高级应用案例。例如,“Five ways to maximize Java NIO and NIO.2” 提供了五个重要的功能介绍,包括变更通知器(Change Notifiers),这使得监听事件变得更加简单。 #### 4. **实际应用场景** 通过结合实例代码可以更好地理解如何利用 Java NIO 实现高性能的数据传输。例如,在文件写入方面有多种实现方法,既可以直接采用标准库中的 `Files` 工具类,也可以借助更底层的 Buffer 和 Channel 结构完成复杂任务[^1]。 ```java import java.nio.file.*; import java.io.IOException; public class FileWriteExample { public static void main(String[] args) throws IOException { Path path = Paths.get("example.txt"); String content = "This is a test."; // 使用 Files.write 方法快速写入字符串到文件 Files.write(path, content.getBytes()); } } ``` 上述代码展示了如何利用 `Files.write()` 函数向指定路径下的文件写入一段文本内容。 --- ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值