• NIO的缓冲区、通道、选择器关系理解


    Buffer的数据存取

       一个用于特定基本数据类行的容器。有java.nio包定义的,所有缓冲区都是抽象类Buffer的子类。
      Java NIO中的Buffer主要用于与NIO通道进行交互,数据是从通道读入到缓冲区,从缓冲区写入通道中的。
      Buffer就像一个数组,可以保存多个相同类型的数据。根据类型不同(boolean除外),有以下Buffer常用子类:ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer

    Buffer的概述

    1)容量(capacity):表示Buffer最大数据容量,缓冲区容量不能为负,并且建立后不能修改。
    2)限制(limit):第一个不应该读取或者写入的数据的索引,即位于limit后的数据不可以读写。缓冲区的限制不能为负,并且不能大于其容量(capacity)。
    3)位置(position):下一个要读取或写入的数据的索引。缓冲区的位置不能为负,并且不能大于其限制(limit)。
    4)标记(mark)与重置(reset):标记是一个索引,通过Buffer中的mark()方法指定Buffer中一个特定的position,之后可以通过调用reset()方法恢复到这个position。

    public class Test {
    
    	public static void main(String[] args) {
    		// 1.指定缓冲区大小1024
    		ByteBuffer buf = ByteBuffer.allocate(1024);
    		System.out.println("--------------------");
    		System.out.println(buf.position());
    		System.out.println(buf.limit());
    		System.out.println(buf.capacity());
    		// 2.向缓冲区存放5个数据
    		buf.put("abcd1".getBytes());
    		System.out.println("--------------------");
    		System.out.println(buf.position());
    		System.out.println(buf.limit());
    		System.out.println(buf.capacity());
    		// 3.开启读模式
    		buf.flip();
    		System.out.println("----------开启读模式...----------");
    		System.out.println(buf.position());
    		System.out.println(buf.limit());
    		System.out.println(buf.capacity());
    		byte[] bytes = new byte[buf.limit()];
    		buf.get(bytes);
    		System.out.println(new String(bytes, 0, bytes.length));
    		System.out.println("----------重复读模式...----------");
    		// 4.开启重复读模式
    		buf.rewind();
    		System.out.println(buf.position());
    		System.out.println(buf.limit());
    		System.out.println(buf.capacity());
    		byte[] bytes2 = new byte[buf.limit()];
    		buf.get(bytes2);
    		System.out.println(new String(bytes2, 0, bytes2.length));
    		// 5.clean 清空缓冲区  数据依然存在,只不过数据被遗忘
    		System.out.println("----------清空缓冲区...----------");
    		buf.clear();
    		System.out.println(buf.position());
    		System.out.println(buf.limit());
    		System.out.println(buf.capacity());
    		System.out.println((char)buf.get());
    	}
    
    }
    
    
    • make与rest用法
    public class Test01 {
    
    	public static void main(String[] args) {
    		ByteBuffer buf = ByteBuffer.allocate(1024);
    		String str = "abcd1";
    		buf.put(str.getBytes());
    		// 开启读取模式
    		buf.flip();
    		byte[] dst = new byte[buf.limit()];
    		buf.get(dst, 0, 2);
    		buf.mark();
    		System.out.println(new String(dst, 0, 2));
    		System.out.println(buf.position());
    		buf.get(dst, 2, 2);
    		System.out.println(new String(dst, 2, 2));
    		System.out.println(buf.position());
    		buf.reset();
    		System.out.println("重置恢复到mark位置..");
    		System.out.println(buf.position());
    	}
    
    }
    
    

    通道Channel

    1. 通道可以同时进行读写,而流只能读或者只能写

    2. 通道可以实现异步读写数据

    3. 通道可以从缓冲读数据,也可以写数据到缓冲:

    • 分散读取与聚集写入
      分散读取:将通道中的数据分散到多个缓冲区中

      聚集写入:将多个缓冲区的数据聚集到通道中

    直接缓冲区与非直接缓冲区别

    • 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中
    // 1.利用通道完成文件的复制(非直接缓冲区)
    	static public void test1() throws IOException { // 4400
    		long start = System.currentTimeMillis();
    		FileInputStream fis = new FileInputStream("e://1.jpg");
    		FileOutputStream fos = new FileOutputStream("e://2.jpg");
    		// ①获取通道
    		FileChannel inChannel = fis.getChannel();
    		FileChannel outChannel = fos.getChannel();
    		// ②分配指定大小的缓冲区
    		ByteBuffer buf = ByteBuffer.allocate(1024);
    		while (inChannel.read(buf) != -1) {
    			buf.flip();// 切换为读取数据
    			// ③将缓冲区中的数据写入通道中
    			outChannel.write(buf);
    			buf.clear();
    		}
    		outChannel.close();
    		inChannel.close();
    		fos.close();
    		fis.close();
    		long end = System.currentTimeMillis();
    		System.out.println(end - start);
    	}
    
    
    • 直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率
    // 使用直接缓冲区完成文件的复制(内存映射文件)
    	static public void test2() throws IOException {
    		long start = System.currentTimeMillis();
    		FileChannel inChannel = FileChannel.open(Paths.get("e://1.jpg"), StandardOpenOption.READ);
    		FileChannel outChannel = FileChannel.open(Paths.get("e://2.jpg"), StandardOpenOption.WRITE,
    				StandardOpenOption.READ, StandardOpenOption.CREATE);
    		// 内存映射文件
    		MappedByteBuffer inMappedByteBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
    		MappedByteBuffer outMappedByteBuffer = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
    		// 直接对缓冲区进行数据的读写操作
    		byte[] dsf = new byte[inMappedByteBuf.limit()];
    		inMappedByteBuf.get(dsf);
    		outMappedByteBuffer.put(dsf);
    		inChannel.close();
    		outChannel.close();
    		long end = System.currentTimeMillis();
    		System.out.println(end - start);
    	}
    
    

    Selector

    一个组件,可以检测多个NIO channel,看看读或者写事件是否就绪。

    多个Channel以事件的方式可以注册到同一个Selector,从而达到用一个线程处理多个请求成为可能。

    非阻塞IO数据准备就绪之后,由选择器发通知给服务器端,数据在准备之前服务器无需等待

  • 相关阅读:
    [原创软件]友盟自动添加版本工具
    【Python3.6+Django2.0+Xadmin2.0系列教程之三(入门篇-下)】学生信息管理系统
    【Python3.6+Django2.0+Xadmin2.0系列教程之二(入门篇-中)】学生信息管理系统
    [原创软件]PC端与移动端文件信息互通工具
    【Python3.6+Django2.0+Xadmin2.0系列教程之一(入门篇-上)】环境搭建及项目创建
    [原创软件]考勤查询工具
    [原创软件]友盟自定义事件批量上传器
    [原创软件]全线升级管理平台
    三步走起 提升 iOS 审核通过率 下篇
    三步走起 提升 iOS 审核通过率 上篇
  • 原文地址:https://www.cnblogs.com/Libbo/p/11570153.html
Copyright © 2020-2023  润新知