正常下班,文章走起。通过前面几篇文章对网络基础知识和网络编程有了认识。接下来这篇文章表述和Netty更加息息相关的知识-NIO。每天学习一小时,期待质变来临。
NIO又称为非阻塞IO,是JDK1.4提出的新的IO模型。
01NIO组件基本介绍
1 Buffer概述(缓冲区)
按照物理分区:直接缓冲区和堆字节缓冲区。Buffer模式:写模式和读模式 。
2 Buffer执行原理分析
三个属性(Buffer的三个属性)capacity(容量)、position(位置)、limit(限制)
b 写模式
![6fc08e75adc2f52b5b027a01d8faf36d.png](https://i-blog.csdnimg.cn/blog_migrate/a8301ea0f6848251521682c74ff3ba89.png)
capacity:数组中可以存储元素的个数
position:下一次可插入元素位置,默认值为0,每添加一个元素都向后移动一位,最大值:capacity - 1
limit:在写的模式下,limit表示第一个不可写的位置(默认第一个不可写的位置,应该是数组容量值得下一个位置,即默认值为capacity)
c 读模式
![c3715961cacd122e66f36ed9915fffda.png](https://i-blog.csdnimg.cn/blog_migrate/98d5488725d8038e62c69da7ba971a2d.png)
capacity:数组中可以存储元素的格数。
position:Buffer由写模式变化为读模式,position会从置0,在进行读取数据时,position向前移动到下一个可读的位置。
limit:第一个不可读位置,当写模式切换到读模式,limit设置写模式下的position值。即能读到之气那所有写入的数据。
2 Channnl(通道)
1 概述类似于流进行数据传输,但是和流不同。流是单向的,大部分功能比较单一,要么进行读要么进行写。通道的使用必须要结合Buffer。
![2d507aaf666e571065e7b4f55e2dc032.png](https://i-blog.csdnimg.cn/blog_migrate/4c55f64f8c21e3516919a08f6fc0dac2.png)
3 Selector(选择器)
概述 每一个通道都存在一个线程对其处理。在高并发情况下,就会存在很多通道,就会创建很多线程对象,造成内存占用率升高,增加cpu在多个线程之间切换的时间。因此不使用高并发场景下。
![b1919c35dd42eaaedbb7bcfba9eee4f0.png](https://i-blog.csdnimg.cn/blog_migrate/7482bd3b91ab641d67c90b9dfd6d5c31.png)
NIO使用通道的改良
我一个线程处理多个任务通道的任务的机制,在NIO中成为多路复用。使用后IO复用后,只需一个线程能对多个通道进行处理,对于高并发的业务场景有优势。补充如下:
线程数随着通道多少进行动态的增减来进行适配。多路复用的核心目的使用最少的线程数去操作更多的通道。创建线程的个数根据通道个数来决定。每注册1023个通道就创建一个线程
![ed54982d77c54cec3f069f48dd08527f.png](https://i-blog.csdnimg.cn/blog_migrate/007a8d9ffd001a14e2a6df18e015b78e.png)
02 NIO实例
public class SocketNioServer {
public static void main(String[] args) throws Exception {
//定义通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//绑定地址
serverSocketChannel.bind(new InetSocketAddress("127.0.0.1", 8080));
//设置为非阻塞模式
serverSocketChannel.configureBlocking(false);
//开启一个选择器
Selector selector = Selector.open();
//注册
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
System.out.println("等待连接,阻塞中.....");
int count = selector.select();
if (count != 0) {
Set<SelectionKey> selectionKeys = selector.selectedKeys();
//遍历集合
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
//客户端已经连接,尚未发送数据
if (selectionKey.isAcceptable()) {
System.out.println("客户端已经连接,尚未发送数据....");
//获取通道
ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = ssc.accept();
//设置非阻塞
socketChannel.configureBlocking(false);
//注册到选择器
socketChannel.register(selector, SelectionKey.OP_READ);
}
//任务就绪
else if (selectionKey.isReadable()) {
System.out.println("客户端成功发送数据");
//获取通道
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
//读取信息
ByteBuffer buffer = ByteBuffer.allocate(1024);
int read = socketChannel.read(buffer);
while (read > 0) {
//切换缓冲区的模式
buffer.flip();
System.out.println(new String(buffer.array(), 0, read));
//清除缓冲区
buffer.clear();
read = socketChannel.read(buffer);
}
socketChannel.close();//释放资源
}
iterator.remove();
}
}
}
}
}
END
个人简介
在上班之余,学习黑马架构课程一段时间了。持续的分享一些干货,如:Netty、MySQL、缓存、中间件、中台、自动化部署、设计模式、JVM、Spring源码、MyBatis源码。