前言:撸基础篇系列,避免每次都要从头开始看,写个自己的知识体系树

NIO 核心就是异步, 比如,复制文件,让操作系统去处理,等通知

BIO核心类

一,BIO

NIO基本操作类

Bytebuffer

构建:

用JVM的内存构建:

ByteBuffer.allocate(bufferSize)

用JVM的直接内存构建:

ByteBuffer.allocateDirect(bufferSize)

内存结构:

 flip()后-->

postion, limit,和captain的处理工具类

flip()    如上, postion=0, limit = wirtCont, captian不变
mark()与reset()方法连用,mark一个postion后,可以通过reset方法返回到原来的订单

缓存的数据处理类
clear()     方法会清空整个缓冲区。

compact()方法只会清除已经读过的数据(0到posstion)

CharSet

用于构建String 和ByteBuffer,以及编码的的一个转换类

构建:
Charset charSet = Charset.forName("gbk");

charSet.decode(butBf)  ,  用于byteBuffer to String

charSet.encode("测试下")  用于String to byteBuffer

	public static void main(String[] args) throws Exception {
FileInputStream finput = new FileInputStream("E://test.txt");
FileChannel fchannel = finput.getChannel();
ByteBuffer byteBf = ByteBuffer.allocate(1024);
fchannel.read(byteBf);
Charset charSet = Charset.forName("utf-8");
byteBf.flip();
System.out.println(charSet.decode(byteBf)); }

  

网络NIO基本操作

selector

一个轮询,实现了 SelectableChannel 接口的都可以在select上添加感兴趣的事件

NBlocking IO,网络服务

/**
* selector 只是一个通知,具体各个部分自行处理
*
* NIO , 不阻塞,当有东西来了就开始通知处理,不然能一直select到·
*
* @author hejb
*
*/
public class Test {
public static void main(String[] args) throws Exception {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 阻塞为false
serverSocketChannel.configureBlocking(false);
// 绑定IP和端口
serverSocketChannel.socket().bind(new InetSocketAddress("0.0.0.0", 8080));
Selector selector = Selector.open();
// 注册感兴趣事件到selector
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select() != 0) { Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) { // 循选中事件
SelectionKey selecttionKey = iterator.next();
// 删除已经处理
iterator.remove();
if (selecttionKey.isAcceptable()) {
// 返回注册该事件时的channel ,即SelectableChannel
ServerSocketChannel channel = (ServerSocketChannel) selecttionKey.channel();
// 有连接事件来了, 可以处理接收请求了,注意如果不进行accept,select.select()一直能轮询到东西
// 接收后返回了个socketchannel,开始配置
SocketChannel socketChannel = channel.accept();
// 也配置成非阻塞处理
socketChannel.configureBlocking(false);
// 复用同一个selector上注册感兴趣的事件,并注册感兴趣的可读事件
socketChannel.register(selector, selecttionKey.OP_READ);
}
// 如果来可以可读事件
if (selecttionKey.isReadable()) {
// 返回注册该事件时的channel ,即实现了SelectableChannel的
SocketChannel socketChannel = (SocketChannel) selecttionKey.channel();
// 后面就都是通过byteBuffer和channel来读操作了
ByteBuffer byteBf = ByteBuffer.allocate(1024);
socketChannel.read(byteBf);
Charset charset = Charset.forName("utf-8");
byteBf.flip();
System.out.println("clinet :" + charset.decode(byteBf));
// socket是双通道,故也可以直接返回东西了
socketChannel.write(charset.encode("test only"));
}
}
}
}
// 有个疑问,NIO的链接什么时候关闭呢,有文章说是在finalize方法里,待我去找找
}

  

那么什么时候用IO,什么时候用NIO呢?

大量链接涌入的时候,传的数据比较少,然后处理时间比较长,的时候适合NIO(偏向IO密集型)

如果传入的链接比较少,然后传输数据量大,比如文件上传之类,适合BIO

NIO的网络模型:

用一个thread(selector)做服务接收,和链接的维持

IO的网路模型

用一个thread做服务接收,其它每个链接都用一条线程保持

文件操作流部分

NIO主要是引入了缓冲区和映射来操作文件

JAVA操作文件的过程

1, JAVA读取-> 2,调用native读取--> 3, 调用系统读取(切换到内核态)->  4,磁盘读取文件

每一层都有设置缓存, JAVA操作上的分类

先说缓冲区,以前的IO中也有缓冲区,如 BufferedInputStream

传统BIO的缓存操作

BIO流的设计,先看连个读取文件例子

没有缓存的FileInputStream

public static String readFileWithoutBuffer() throws IOException {
// BIO inputstream without buffer
FileInputStream input = new FileInputStream("E://test.txt");
byte[] content = new byte[1024];
int length = input.read(content);
input.close();
return new String(content, 0, length);
}

读取文件时,read的实现是直接通过调用系统的读取数据(native),就是每次读取时都要调用到系统读取。

带缓存的BufferedInputStream

public static String readFileWithBuffer() throws IOException {
// BIO inputstream with buffer
FileInputStream input = new FileInputStream("E://test.txt");
BufferedInputStream binpt = new BufferedInputStream(input);
byte[] bufferContent = new byte[1024];
int length = binpt.read(bufferContent);
return new String(bufferContent, 0, length);
}

BufferedInputStream是通过内部缓冲区数组实现的缓冲,每次读取时先返回内部数组的数据,默认大小是8192。

具体点用了Decorator模式,继承自FileInputStream ,(覆盖)装饰read方法

代码段:

 public synchronized int read() throws IOException {
if (pos >= count) {
fill(); // 如果读取大于缓存了,填充缓冲buff
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
}

结论:

BufferedInputStream 的作用不是减少 磁盘IO操作次数(这个OS已经帮我们做了),而是通过减少系统调用次数来提高性能的。

NIO的文件映射操作

总结下JAVA文件操作

顺序读取
1, InputStream/OutputStream - 直接调用native方法
2, BufferedInputStream/BufferedOutputStream-  在类里维护了个byte[],先缓存读取到byte中(装饰器的模式)

随机读取
3,RandomAccessFile  - 直接调用native方法
4,FileChannel      -系统的虚拟内存映射文件,讲文件映射到内存中当数组操作

各种文件读取适用场景

--转个实验

在Core Java II中进行了这么一个实验:在同一台机器上,对JDK的jre/lib目录中的37MB的rt.jar文件分别用以上四种操作来计算CRC32校验和,记录下了如下时间

    方法     时间
  普通输入流     110s        
  带缓冲的输入流       9.9s
  随机访问文件     162s
  内存映射文件     7.2s

  这个小实验也验证了内存映射文件这个方法的可行性,由于具有随机访问的功能(映射在内存数组),所以常用来替代RandomAccessFile。

  当然,对于中等尺寸文件的顺序读入则没有必要使用内存映射以避免占用本就有限的I/O资源,这时应当使用带缓冲的输入流。

欢迎关注我的公众号, 一起来构建我们的知识体系

撸基础篇系列,JAVA的NIO部分的更多相关文章

  1. 【目录】mysql 基础篇系列

    随笔分类 - mysql 基础篇系列 mysql 开发基础系列22 SQL Model(带迁移事项) 摘要: 一.概述 与其它数据库不同,mysql 可以运行不同的sql model 下, sql m ...

  2. oracle(sql)基础篇系列(五)——PLSQL、游标、存储过程、触发器

      PL/SQL PL/SQL 简介 每一种数据库都有这样的一种语言,PL/SQL 是在Oracle里面的一种编程语言,在Oracle内部使用的编程语言.我们知道SQL语言是没有分支和循环的,而PL语 ...

  3. oracle(sql)基础篇系列(五)——PLSQL、游标、存储过程、触发器

    PL/SQL PL/SQL 简介 每一种数据库都有这样的一种语言,PL/SQL 是在Oracle里面的一种编程语言,在Oracle内部使用的编程语言.我们知道SQL语言是没有分支和循环的,而PL语言是 ...

  4. 基础篇系列,JAVA的并发包 - 锁

    JAVA中主要锁 synchronized Reentrantlock ReentrantReadWriteLock 问题引入 为什么需要锁? 为什么JAVA有了synchronize还需要Reent ...

  5. 基础篇:JAVA集合,面试专用

    没啥好说的,在座的各位都是靓仔 List 数组 Vector 向量 Stack 栈 Map 映射字典 Set 集合 Queue 队列 Deque 双向队列 关注公众号,一起交流,微信搜一搜: 潜行前行 ...

  6. oracle(sql)基础篇系列(一)——基础select语句、常用sql函数、组函数、分组函数

        花点时间整理下sql基础,温故而知新.文章的demo来自oracle自带的dept,emp,salgrade三张表.解锁scott用户,使用scott用户登录就可以看到自带的表. #使用ora ...

  7. Spring基础篇——通过Java注解和XML配置装配bean

    自动化装配的确有很大的便利性,但是却并不能适用在所有的应用场景,比如需要装配的组件类不是由自己的应用程序维护,而是引用了第三方的类库,这个时候自动装配便无法实现,Spring对此也提供了相应的解决方案 ...

  8. oracle(sql)基础篇系列(一)——基础select语句、常用sql函数、组函数、分组函数

    花点时间整理下sql基础,温故而知新.文章的demo来自oracle自带的dept,emp,salgrade三张表.解锁scott用户,使用scott用户登录就可以看到自带的表. #使用oracle用 ...

  9. Spring基础篇——通过Java注解和XML配置装配bean(转载)

      作者:陈本布衣 出处:http://www.cnblogs.com/chenbenbuyi 本文版权归作者和博客园共有,欢迎转载分享,但必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留 ...

随机推荐

  1. grunt安装详解及失败处理

    标签: 1.官网 nodejs官网 https://nodejs.org/en/ Grunt官网 http://gruntjs.com/ Grunt插件首页  http://gruntjs.com/p ...

  2. Bmob 之 简单使用

    1. pod pod 'BmobSDK' 与 pod "BmobSDK" 好像没什么区别 2. 导入 在AppDelegate中: #import <BmobSDK/Bmob ...

  3. HDU-2077-汉诺塔IV

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2077 这题就我个人认为比较难,做了很久,递推关系式一直找不出正确的来,找很多递推关系,提交了很多次,全 ...

  4. RAC时间同步的两种方法

    集群时间同步服务在集群中的两个 Oracle RAC 节点上执行以下集群时间同步服务配置.Oracle Clusterware 11g 第 2 版及更高版本要求在部署了 Oracle RAC 的集群的 ...

  5. 《深度探索C++对象模型》笔记——Function语意学

    member的各种调用方式 C++支持三种类型的member functions:static.nonstatic和virtual. nonstatic member functions会被编译器转换 ...

  6. 基于basys2驱动LCDQC12864B的verilog设计图片显示

    话不多说先上图 前言 在做这个实验的时候在网上找了许多资料,都是关于使用单片机驱动LCD显示,确实用单片机驱动是要简单不少,记得在FPGA学习交流群里问问题的时候,被前辈指教,说给我最好的指教便是别在 ...

  7. SimRank协同过滤推荐算法

    在协同过滤推荐算法总结中,我们讲到了用图模型做协同过滤的方法,包括SimRank系列算法和马尔科夫链系列算法.现在我们就对SimRank算法在推荐系统的应用做一个总结. 1. SimRank推荐算法的 ...

  8. [CSS3] 学习笔记-CSS3盒子样式

    1.盒子的类型 在CSS3中,使用display来定义盒子的类型,包括block,inline,inline-block类型.div元素和P元素,属于block类型,span元素和a元素,属于inli ...

  9. SQL CRUD 简单查询

    identity 自增长 primary key 主键 unique 唯一键 not null 非空 references 外键(引用) 1.删除表 drop table Student 2.修改表 ...

  10. 使用LVS实现负载均衡原理及安装配置详解

    负载均衡集群是 load balance 集群的简写,翻译成中文就是负载均衡集群.常用的负载均衡开源软件有nginx.lvs.haproxy,商业的硬件负载均衡设备F5.Netscale.这里主要是学 ...