设计一个个人网站的基本步骤,百度2019旧版本下载,傻瓜式建个人网站,广州网络推广公司电话一 简介 1 三大模型是什么#xff1f; IO三大模型之一#xff0c;BIO#xff0c;AIO#xff0c;还有我们的主角NIO(non-blocking-io)#xff0c;也就是同步非阻塞式IO。这三种模型到底是干什么的#xff1f;其实这三种模型都是对于JAVA的一种I/O框架#xff0c;用来进行…一 简介 1 三大模型是什么 IO三大模型之一BIOAIO还有我们的主角NIO(non-blocking-io)也就是同步非阻塞式IO。这三种模型到底是干什么的其实这三种模型都是对于JAVA的一种I/O框架用来进行输入输出操作。另一方面以上三种模型提供的是统一的API操作可以理解为JAVA针对于各种操作系统的IO模型进行的封装从而具有一定的跨平台性等。作为开发者我们不需要再了解有关操作系统层面的知识直接使用这三种框架封装的API进行使用即可 2 NIO NIONew Input/Output是Java中的一种I/O输入/输出框架主要用于处理异步I/O操作。它在Java 1.4版本中引入旨在提高I/O操作的性能和可扩展性。 NIO的主要特点 非阻塞I/ONIO允许线程在发起I/O操作后继续执行其他任务而不必等待I/O操作完成从而提高了应用的响应性。 选择器SelectorNIO引入了选择器允许单个线程管理多个通道Channel从而减少了资源消耗和上下文切换的开销。 通道ChannelNIO使用通道进行数据的读写通道是双向的可以同时进行读和写操作。 缓冲区BufferNIO使用缓冲区来存储数据缓冲区在读写过程中充当数据的临时存储区。 文件通道FileChannelNIO还提供了文件通道可以用于高效地处理文件I/O。 NIO特别适合于需要处理大量并发连接的网络应用如Web服务器和聊天应用等。通过非阻塞I/O和选择器NIO能够更好地利用系统资源提高整体性能。 二 NIO三大组件 1.Channel通道 相当于我们之前学习IO流操作中的输入输出流起到一个通道的作用。但是在这里这个更加全面既可以充当输入流又可以充当输出流。是为双向通道。channel比Stream更底层双向。 2.Buffer缓冲区 缓冲区作为一个在网络或者是本地文件与计算机之间的桥梁任何数据在进入通道Channel之前都需要经过Buffer。前者可以将数据读入Buffer也可以将Buffer当中的数据写入Channel当中 3.Selector选择器 选择器是NIO中用于处理非阻塞I/O的核心组件。它允许单个线程管理多个通道。 我认为将其与各种服务器设计模式相结合进行介绍会更加清晰。 我们以BIO同步阻塞IO举例这样更加方便理解 我们都知道BIO是一种同步阻塞IO在服务端与客户端之间其会建立一个一个通道Socket以进行彼此之间的数据输入和输出但是对于一个服务端如果想要与多个客户端之间建立连接那么就需要建立多个线程也就是一个线程对应一个客户端。如下图 但是这样存在很大的弊端如果有很多的客户端都进行访问那么就会创建多个线程与其连接就会导致CPU资源被占用许多甚至直接宕机导致客户端无法被外部访问。各个线程上下文之间的来回切换线程创建也会消耗大量资源。这也就是为什么要创建线程池了。。。。另一方面BIO还有一个特点那就是阻塞如果一个客户端没有发送消息那么对应的线程就会一直等待直到客户端发送新的消息才会继续进行执行。在此之前等待的过程就会造成CPU资源的大量占用。所以这种方式只适用于比较少的客户端访问。其实这就是服务器的设计之一 ----- 多线程设计模式 有的大佬就会想到可以创建线程池来处理问题没错我们上面面对的一个大问题就是线程会随着客户端的访问而不断的创建。从而导致资源的大量占用。使用线程池可以设定线程的最大数量用以解决客户端访问过多造成的问题。但是这种解决方式也存在很大问题至于为什么大家可以想一想。 线程池设计模式。顾名思义就是针对之前一个线程对应一个客户端的情形进行该进变为一个线程针对多个客户端进行处理如下 这种设计模式相比多线程有所提高但是因为在阻塞模式下依旧是一个线程在处理时仅仅只能够处理一个客户端也就是Socket连接因此其适合一个线程下连接的Scoket比较少的情况。 Slector版设计模式。selector 的作用就是配合一个线程来管理多个 channel获取这些 channel 上发生的事件这些 channel 工作在非阻塞模式下不会让线程吊死在一个 channel 上。适合连接数特别多但流量低的场景low traffic如下图 这种设计模式一个线程对应一个选择器这个选择器会直接监视其下的所有通道一旦这些通道有什么动作发生选择器就会将其汇报给线程由线程进行解决。 非阻塞的形式也就是说我们选择器监视下的各个通道比如第一个通道如果其当前没有任务那么我们的选择器就不会等待而是直接看下一个通道是否有任务。 适合流量比较低指的就是如果我们的通道一下接收一个比较大的数据那么选择器就会长时间的停留于它直到它的任务结束数据如果比较大也就是如果流量比较大那么就会影响其他通道的正常使用因此适用于流量比较低的场景。 由此可见选择器适合于事件驱动的应用程序可以有效地处理大量并发连接减少线程上下文切换的开销。 三 Buffer - ByteBuffer 上面我们简单说了几个比较缓冲区的Buffer但是比较常用的实际上就一个ByteBuffer所以我们拿这个作为详细介绍 1.基本使用
Slf4j
public class ChannelDemo1 {public static void main(String[] args) {try (RandomAccessFile file new RandomAccessFile(helloword/data.txt, rw)) {FileChannel channel file.getChannel();ByteBuffer buffer ByteBuffer.allocate(10);do {// 向 buffer 写入int len channel.read(buffer);log.debug(读到字节数{}, len);if (len -1) {break;}// 切换 buffer 读模式buffer.flip();while(buffer.hasRemaining()) {log.debug({}, (char)buffer.get());}// 切换 buffer 写模式buffer.clear();} while (true);} catch (IOException e) {e.printStackTrace();}}
} 以上使用通道FileChannel与Buffer进行了一个简单的文件读取以及对应文件内容的日志打印。 2.BetyBuffer使用说明 向 buffer 写入数据例如调用 channel.read(buffer) 调用 flip() 切换至读模式 从 buffer 读取数据例如调用 buffer.get() 调用 clear() 或 compact() 切换至写模式 重复 1~4 步骤 3.ByteBuffer结构 其内部实际上是一个类似数组的存储结构数组的长度也就是我们在使用allocate方法的时候自定义的。 ByteBuffer主要有三个比较重要的属性 position当前位置 limit限制 capaciy为数组容量 刚开始写入数据操作 在我们刚开始进行数据写入操作的时候position从头开始后两个都在最后每写入一个数据对应的position指针就会向后移动一位如图。 获取数据 使用filp获取数据的时候对应的position指针就会从头开始索引归零取而代之的是limit用来代替之前写入的数据的最大索引位置为了防止读取出来的数据为空。 clear动作发生之后会将数组内部的所有元素都清空变为空从头来过重新进行写操作。 还有一种写操作为compact动作比如我们因为某种原因之前没有读取完的数据那么就会直接将其进向前压缩并且更新对应读取的时候的Position以及Limit的位置。从而达到写的操作。