目录

NIO(一、概述)

NIO(二、Buffer)

NIO(三、Channel)

NIO(四、Selector)

Buffer

前文讲了NIO与IO的区别,那么这一章开始讲述NIO下核心类 - Buffer类

  上一章就说过,NIO的核心包括三个部分:通道(Channel)、选择器(Selector)、缓冲区(Buffer),尽管还有其它的部分,例如管道(Pipe)、文件锁(FileLock)、字符集(Charset)或甚是java.nio包下的异常类,这些都是作为工具而被使用。

  说起缓冲区,我们都知道是临时数据存储的地方,官方给它的定义是:

A container for data of a specific primitive type. 特定基础类型数据的容器

  其实我们看它的实现类就能看出来

  • ByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

  几乎每种基础数据类型都会有一种Buffer的实现,它们的操作方式几乎一致,都有读(get)/写(put)操作,而且都是抽象类,所以,基于这些基础类型的缓冲区,还有更具体的实现,例如ByteBuffer类有HeapByteBuffer和MappedByteBuffer两个子类。第一次阅读代码可能有些奇怪,既然所有基础类型数据的缓冲区都从Buffer类继承,那么Buffer类中并没有抽象出读(get)/写(put)方法,而是每个子类中分别抽象本身类型的读(get)/写(put)操作。同样分配缓冲区大小方法( allocate() )也是在子类中定义,Buffer类本身并没对外提供任何初始化的方法,即便是构造也是为了子类继承使用,由此可见,在使用Buffer的时候,我们应该明确知道该使用哪一类基础类型的缓冲区。

Capacity、Limit、Position

  我们阅读Buffer类代码会发现,Buffer类定义四个int类型的私有字段:mark、position、limit、capacity。其实了解完这四个字段,我们就明白Buffer是如何工作的。

无论如何,它们的大小都会遵照这个规则 :mark <= position <= limit <= capacity

  这是Buffer读/写模式时position、limit、capacity的图。

  我们看一段简单代码:

//code
IntBuffer intBuffer = IntBuffer.wrap(new int[]{1, 2, 3, 4, 5, 6, 7});
System.out.println("capacity -> " + intBuffer.capacity());
System.out.println("limit -> " + intBuffer.limit());
System.out.println("position -> " + intBuffer.position());
//切换读模式
intBuffer.flip();
System.out.println("capacity -> " + intBuffer.capacity());
System.out.println("limit -> " + intBuffer.limit());
System.out.println("position -> " + intBuffer.position());
//console:
//写模式
capacity -> 7
limit -> 7
position -> 0
//读模式
capacity -> 7
limit -> 0
position -> 0

  初始化了一个IntBuffer对象,然后打印capacity、limit、position的值,清楚的可以看到,capacity和limit初始值是初始化容量的大小,position为0。当切换读模式时,capacity的值同样为7,limit和position值为0。

  接上一段代码:

//code
intBuffer.clear();
intBuffer.put(100);
intBuffer.put(200);
System.out.println("position -> " + intBuffer.position());
//切换读模式
intBuffer.flip();
int pVal0 = intBuffer.get(0);
System.out.println("capacity -> " + intBuffer.capacity());
System.out.println("limit -> " + intBuffer.limit());
System.out.println("position -> " + intBuffer.position());
//console
position -> 2
//读模式
capacity -> 7
limit -> 2
position -> 0

  position就是你在往Buffer中写数据时,标示当前的位置,初始化的position肯定是0,当你写入一个数据,position就会增加1。但我们发现我们读操作并不会改变position的值,因为get操作只会检查索引有无越界,然后取出数据,并不像put操作会把position增加1。

  另外,要说明一下的是,mark也是Buffer中的一个标记,当缓冲区初始化时、设置新的position或limit的值时、清理缓冲区时、设置读模式时等,mark值都会被标为-1。仅仅在使用mark()方法的时候,mark字段才会被赋予position值。mark作为position的一个临时存储的变量而存在,我们随时都可以调用reset()把之前存储的原position值重新赋给position变量。当一个position不够用时,我们需要多一个临时变量存储,这似乎就是mark存在的意义了。

  同样,我们也发现capactiy就是缓冲区的容量,缓冲区的容量在初始化之后就不会变,无论你执行clear()或是compact()方法,它们都不会改变缓冲区的容量,除非被回收整个缓冲区。当我们初始化一个缓冲区之后,在明知道容量只有3的情况下,却硬是塞4个值,那么运行会抛出java.nio.BufferOverflowException异常。

  接上一段代码:

System.out.println("limit -> " + intBuffer.limit());
//code 1.1
intBuffer.get(5);
System.out.println("limit -> " + intBuffer.limit());
//code 1.2
intBuffer.limit(intBuffer.capacity());
intBuffer.get(5);
System.out.println("limit -> " + intBuffer.limit()); //console
limit -> 2
//code 1.1
java.lang.IndexOutOfBoundsException
//code 1.2
limit -> 7

  limit同样标示使用的上限,表示你能写多少数据,或你能读多少数据的值。换句话说,就是读/写的时候,limit大小决定了你能读/写多少。上述代码说明了这一点,进入代码块时limit的值为2,意味着只能读索引为0或1的数据,只有当limit被重新赋值,你才能读取新值范围以内的数据。

线程安全

  Buffer类的实现,决定了这必定是线程不安全的,如果需要在多个线程中使用,我们需要主动加上同步控制。

方法

  这里只介绍几个比较重要的操作方法。

  flip(),切换读模式。

public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}

  rewind(),重读,可以理解成倒带,即便已读过的数据内容也可重读一遍。

public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}

  clear(),清除缓冲区内容,可以将新的数据重新写进缓冲区.。

public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}

NIO(二、Buffer)的更多相关文章

  1. java学习-NIO(二)Buffer

    当我们需要与 NIO Channel 进行交互时, 我们就需要使用到 NIO Buffer, 即数据从 Buffer读取到 Channel 中, 并且从 Channel 中写入到 Buffer 中.缓 ...

  2. Java NIO 之 Buffer(缓冲区)

    一 Buffer(缓冲区)介绍 Java NIO Buffers用于和NIO Channel交互. 我们从Channel中读取数据到buffers里,从Buffer把数据写入到Channels. Bu ...

  3. Java NIO 之 Buffer

    Java NIO 之 Buffer Java NIO (Non Blocking IO 或者 New IO)是一种非阻塞IO的实现.NIO通过Channel.Buffer.Selector几个组件的协 ...

  4. Java NIO之Buffer(缓冲区)

    ​ Java NIO中的缓存区(Buffer)用于和通道(Channel)进行交互.数据是从通道读入缓冲区,从缓冲区写入到通道中的. ​ 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这 ...

  5. java nio之Buffer(一)

    Buffer是一个包装了基本数据元素数组的对象,它以及它的子类定义了一系列API用于处理数据缓存. 一.属性 Buffer有四个基本属性: 1.capacity  容量,buffer能够容纳的最大元素 ...

  6. 【Java nio】buffer

    package com.slp.nio; import org.junit.Test; import java.nio.ByteBuffer; /** * Created by sanglp on 2 ...

  7. java nio之Buffer

    一.JAVA NIO 是在和channel交互的时候使用的.Channel将数据读入缓冲区,然后我们又从缓冲区访问数据.写数据时,首先将要发送的数据按顺序填入缓冲区.基本上,缓冲区只是一个列表,它的所 ...

  8. 《精通并发与Netty》学习笔记(15 - 详解NIO中Buffer之position,limit,capacity)

    一.前言熟悉NIO的人想必一定不会陌生buffer中position,limit,capacity这三个属性吧,之前在学习的时候遇到一个问题:就是当你先往缓冲区写入一部分数据,然后调用flip()方法 ...

  9. 《精通并发与Netty》学习笔记(11 - 详解NIO (二) 分散/聚集 Scatter/Gather、Selector)

    一.分散/聚集 Scatter/Gather scatter/gather指的在多个缓冲区上实现一个简单的I/O操作,比如从通道中读取数据到多个缓冲区,或从多个缓冲区中写入数据到通道:scatter( ...

  10. NIO(二):Channel通道

    一.Channel概述 channel(通道):进行IO的连接通道,为NIO的几个核心(Buffer,selector,channel)之一,相比于IO的stream具有较高的性能. IO 单向传输 ...

随机推荐

  1. SoapUI:mock service的使用

    mock service就是服务模拟,当我们的接口完成而服务端还没完成的时候,我们就可以用mock service来替代服务端进行接口测试. 1.1       创建MockService 创建moc ...

  2. 2017qq红包雨最强攻略,

    这个只支持苹果手机,而且要有苹果电脑,只有苹果手机是不行的. QQ红包规则:只要你到达指定的位置,就可以领取附近的红包,一般也就几毛,还有几分的,当然也不排除有更高的,只不过我是没遇到... 那么既然 ...

  3. 爱你不容易 —— Stream详解

    作为前端,我们常常会和 Stream 有着频繁的接触.比如使用 gulp 对项目进行构建的时候,我们会使用 gulp.src 接口将匹配到的文件转为 stream(流)的形式,再通过 .pipe() ...

  4. 设备文件三大结构:inode,file,file_operations

    驱动程序就是向下控制硬件,向上提供接口,这里的向上提供的接口最终对应到应用层有三种方式:设备文件,/proc,/sys,其中最常用的就是使用设备文件,而Linux设备中用的最多的就是字符设备,本文就以 ...

  5. http-server 使用介绍

    做一个项目的时候需要服务环境,又不想使用apache,php,于是找到一款比较简单的易用的webserver 就是http-server 首先介绍一个怎么使用吧,http-server 是基于node ...

  6. 如何用CSS进行网页布局---学习总结

    页面布局:对页面的文字.图形或表格进行格式设置.包括字体.字号.颜色纸张大小和方向以及页边距等 页面布局分为4种: 一栏布局 两栏布局 三栏布局 混合布局 灵活利用float.position对页面进 ...

  7. Java中boolean类型到底占用多少字节

    虽然 Java 虚拟机定义了 boolean 这种数据类型,但是只对它提供了非常有限的支持.在 Java 虚拟机中没有任何供 boolean 值专用的字节码指令,在 Java 语言之中涉及到 bool ...

  8. Dirty Flag 模式及其应用

    之前在开发中就发现"dirty"是一种不错的解决方案:可以用来延缓计算或者避免不必要的计算.后来在想,这应该也算一种设计模式吧,于是搜索"Dirty设计模式", ...

  9. LNMP系统服务搭建过程详解

    和LAMP不同的是LNMP中的N指的是Nginx(类似于Apache的一种web服务软件)其他都一样.目前这种环境应用的也是非常之多.Nginx设计的初衷是提供一种快速高效多并发的web服务软件.在静 ...

  10. linux 下安装eclipse和pydev插件用来开发python程序

    1.网上的教程要求必须要安装java虚拟机,但是我觉得不用,但是为了不出意外就装吧. (1)去官网下载安装包www.sun.com (2)安装包是.tar.gz的可以用 tar -xzvf +压缩包路 ...