JAVA NIO基础知识总结二_2012-1-9
java nio原理
java nio原理Java NIO(New IO)是Java SE 1.4版本中添加的一个用于高效处理 I/O 操作的API。
与传统的Java IO API相比,Java NIO提供了更好的可扩展性和可靠性。
在本文中,我们将深入探讨Java NIO的原理。
1. Java NIO的基本组件Java NIO的核心组件由以下四个部分构成:- 缓冲区(Buffer):一个可读写的数据容器,用于存储原始数据。
- 通道(Channel):用于在缓冲区和外部实体(如文件、套接字)之间传输数据。
- 选择器(Selector):非阻塞I/O的关键。
选择器可以同时监听多个通道的I/O事件,从而实现单线程处理多通道数据的能力。
- 选择键(SelectionKey):表示一个通道在选择器中的注册状态及其对应的I/O事件。
2. Java NIO的工作流程- 创建一个Channel实例:选择要使用的通道类型(如FileChannel)。
- 创建一个Buffer实例:指定缓冲区的大小。
- 将数据写入缓冲区:可通过put()方法向缓冲区写入数据。
- 调用flip()方法:将Buffer从写入模式切换到读取模式。
- 将数据从Buffer读取到Channel中:可使用Channel.write()方法将数据从Buffer中写出到通道中。
- 关闭Channel和Buffer实例:在处理完一个数据块后需要关闭Channel和Buffer实例,以释放资源。
3. Java NIO的优势相比传统的Java IO API,Java NIO的主要优势有:- 更快的速度:由于Java NIO使用缓冲区和通道等组件,因此在处理大量数据时,它比Java IO API更快。
- 更少的资源占用:Java NIO使用少量的线程和较少的内存资源,因此它比Java IO API更适合于处理高并发的应用程序。
- 可扩展性强:Java NIO API的原始设计使它易于扩展,因此它适合于开发更复杂的网络应用程序。
java NIO 学习
Java Api nio包学习李君整理1.引言I/O流或者输入/输出流指的是计算机与外部世界或者一个程序与计算机的其余部分的之间的接口。
新的输入/输出(NIO)库是在JDK 1.4中引入的。
NIO弥补了原来的I/O的不足,它在标准Java代码中提供了高速的、面向块的I/O。
原来的I/O库与NIO最重要的区别是数据打包和传输的方式的不同,原来的I/O以流的方式处理数据,而NIO以块的方式处理数据。
面向流的I/O系统一次一个字节地处理数据。
一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。
为流式数据创建过滤器非常容易。
链接几个过滤器,以便每个过滤器只负责单个复杂处理机制的一部分,这样也是相对简单的。
不利的一面是,面向流的I/O通常相当慢。
NIO与原来的I/O有同样的作用和目的,但是它使用块I/O的处理方式。
每一个操作都在一步中产生或者消费一个数据块。
按块处理数据比按(流式的)字节处理数据要快得多。
但是面向块的I/O缺少一些面向流的I/O所具有的优雅性和简单性。
2.从一个例子开始下面我们从一个简单的使用IO和NIO读取一个文件中的内容为例,来进入NIO的学习之旅。
使用IO来读取指定文件中的前1024字节并打印出来:Java代码1/**2*使用IO读取指定文件的前1024个字节的内容。
3*@param file指定文件名称。
4*@throws java.io.IOException IO异常。
5*/6public void ioRead(String file)throws IOException{7FileInputStream in=new FileInputStream(file);8byte[]b=new byte[1024];9in.read(b);10System.out.println(new String(b));11}1213/**14*使用NIO读取指定文件的前1024个字节的内容。
JavaNIO详解(一)
JavaNIO详解(⼀)⼀、基本概念描述1.1 I/O简介I/O即输⼊输出,是计算机与外界世界的⼀个借⼝。
IO操作的实际主题是操作系统。
在java编程中,⼀般使⽤流的⽅式来处理IO,所有的IO都被视作是单个字节的移动,通过stream对象⼀次移动⼀个字节。
流IO负责把对象转换为字节,然后再转换为对象。
关于Java IO相关知识请参考我的另⼀篇⽂章:1.2 什么是NIONIO即New IO,这个库是在JDK1.4中才引⼊的。
NIO和IO有相同的作⽤和⽬的,但实现⽅式不同,NIO主要⽤到的是块,所以NIO的效率要⽐IO⾼很多。
在Java API中提供了两套NIO,⼀套是针对标准输⼊输出NIO,另⼀套就是⽹络编程NIO,本篇⽂章重点介绍标NIO,关于⽹络编程NIO请见。
1.3 流与块的⽐较NIO和IO最⼤的区别是数据打包和传输⽅式。
IO是以流的⽅式处理数据,⽽NIO是以块的⽅式处理数据。
⾯向流的IO⼀次⼀个字节的处理数据,⼀个输⼊流产⽣⼀个字节,⼀个输出流就消费⼀个字节。
为流式数据创建过滤器就变得⾮常容易,链接⼏个过滤器,以便对数据进⾏处理⾮常⽅便⽽简单,但是⾯向流的IO通常处理的很慢。
⾯向块的IO系统以块的形式处理数据。
每⼀个操作都在⼀步中产⽣或消费⼀个数据块。
按块要⽐按流快的多,但⾯向块的IO缺少了⾯向流IO 所具有的有雅兴和简单性。
⼆、NIO基础Buffer和Channel是标准NIO中的核⼼对象(⽹络NIO中还有个Selector核⼼对象,具体请参考),⼏乎每⼀个IO操作中都会⽤到它们。
Channel是对原IO中流的模拟,任何来源和⽬的数据都必须通过⼀个Channel对象。
⼀个Buffer实质上是⼀个容器对象,发给Channel的所有对象都必须先放到Buffer中;同样的,从Channel中读取的任何数据都要读到Buffer中。
2.1 关于BufferBuffer是⼀个对象,它包含⼀些要写⼊或读出的数据。
Java NIO API详解资料
Java NIO API详解NIO API主要集中在java.nio和它的subpackages中:java.nio定义了Buffer及其数据类型相关的子类。
其中被java.nio.channels中的类用来进行IO操作的ByteBuffer的作用非常重要。
java.nio.channels定义了一系列处理IO的Channel接口以及这些接口在文件系统和网络通讯上的实现。
通过Selector这个类,还提供了进行非阻塞IO操作的办法。
这个包可以说是NIO API的核心。
java.nio.channels.spi定义了可用来实现channel和selector API的抽象类。
java.nio.charset定义了处理字符编码和解码的类。
java.nio.charset.spi定义了可用来实现charset API的抽象类。
java.nio.channels.spi和java.nio.charset.spi这两个包主要被用来对现有NIO API进行扩展,在实际的使用中,我们一般只和另外的3个包打交道。
下面将对这3个包一一介绍。
Package java.nio这个包主要定义了Buffer及其子类。
Buffer定义了一个线性存放primitive type数据的容器接口。
对于除boolean以外的其他primitive type,都有一个相应的Buffer子类,ByteBuffer是其中最重要的一个子类。
下面这张UML类图描述了java.nio中的类的关系:Buffer定义了一个可以线性存放primitive type数据的容器接口。
Buffer主要包含了与类型(byte, char…)无关的功能。
值得注意的是Buffer及其子类都不是线程安全的。
每个Buffer都有以下的属性:capacity这个Buffer最多能放多少数据。
capacity一般在buffer被创建的时候指定。
limit在Buffer上进行的读写操作都不能越过这个下标。
nio源码解析
nio源码解析一、引言1.背景介绍在Java 编程中,IO 操作一直是开发者关注的重点。
随着Java 技术的不断发展,Java NIO(New I/O)作为一种全新的IO 处理方式,逐渐成为Java 开发者必备技能。
本文将对Java NIO 进行详细的解析,帮助读者更好地理解和应用这一技术。
2.NIO 概念阐述IO,全称Non-Blocking I/O,中文意为非阻塞IO。
与传统的阻塞IO 不同,NIO 采用了事件驱动模型,使得IO 操作与线程操作分离,从而在处理高并发、高性能场景下具有明显优势。
二、Java NIO 核心API1.ChannelChannel 是Java NIO 的核心接口,代表了一个IO 通道。
它可以用于读写数据,并且支持多种类型的IO 操作。
在Java NIO 中,Channel 分为字节通道(ByteChannel)和字符通道(CharacterChannel)等。
2.BufferBuffer 是Java NIO 的另一个核心接口,用于存储数据。
Buffer 内部采用环形缓冲区实现,可以有效提高数据处理效率。
Buffer 提供了多种方法,方便开发者进行数据的添加、删除和检查等操作。
3.SelectorSelector 是Java NIO 中用于处理多路IO 事件的工具。
通过注册通道(RegisteredChannel )将通道与Selector 关联,然后使用Selector 的select 方法监听IO 事件。
当IO 事件发生时,Selector 会返回一个包含事件通道的集合,开发者可以根据需要进行相应处理。
三、Java NIO 的工作原理1.事件驱动模型Java NIO 采用了事件驱动模型,将IO 操作与线程操作分离。
当IO 操作就绪时,操作系统会通过epoll 等机制通知Java 程序,此时线程可以处理该事件。
这种方式避免了线程的阻塞,提高了程序的并发处理能力。
2.非阻塞IOJava NIO 中的Channel 接口默认采用非阻塞IO。
java-nio讲解
MADE BY 尹千慧
1
NIO是什么东西? NIO与传统IO的区别 NIO构成组件 NIO应用场景
目录
CONTENTS
2 3 4
01
概念:什么是NIO?
概念讲解-初识NIO 1.在 JDK 1. 4 中 新 加入 了 NIO( New Input/ Output) 类, 引入了一种基于通道和缓冲区的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆
1.FileChannel 2.DatagramChannel 3.SocketChannel 4.ServerSocketChannel
FileChannel用于文件的数据读写。 DatagramChannel用于UDP的数据读写。 SocketChannel用于TCP的 数据读写。 ServerSocketChannel允许我们监听TCP链接请求,每个请求会创建会一个SocketChannel.
年积蓄在某城市开了一家100桌大小的火锅店。因为多年的行业浸淫,老王坚信以客户为中心
的思想不动摇。为了做到VIP一般的服务,老王招了50多名服务员,同时还在招了50多名兼职 服务员,以备客人多时用。为什么招这么多呢?因为老王要求每桌标配一名服务员进行服务,
如果50名正式员工不够用,就启用兼职员工。一个多月下来,老王的生意也很火爆,大家觉得
NIO模型图
02
NIO与传统IO的区别
图解说明
IO与NIO对比
IO
NIO
对比一:面向流
பைடு நூலகம்
对比一:面向缓冲 对比二:非阻塞 对比三:selector
对比二:阻塞IO Z 对比三:无
详细对比
JavaNIO原理图文分析及代码实现
JavaNIO原理图⽂分析及代码实现Java IO在Client/Server模型中,Server往往需要同时处理⼤量来⾃Client的访问请求,因此Server端需采⽤⽀持⾼并发访问的架构。
⼀种简单⽽⼜直接的解决⽅案是“one-thread-per-connection”。
这是⼀种基于阻塞式I/O的多线程模型。
在该模型中,Server为每个Client连接创建⼀个处理线程,每个处理线程阻塞式等待可能达到的数据,⼀旦数据到达,则⽴即处理请求、返回处理结果并再次进⼊等待状态。
由于每个Client连接有⼀个单独的处理线程为其服务,因此可保证良好的响应时间。
但当系统负载增⼤(并发请求增多)时,Server端需要的线程数会增加,这将成为系统扩展的瓶颈所在。
()<IMG style="DISPLAY: block; MARGIN-LEFT: auto; MARGIN-RIGHT: auto" title=旧I/O模型,多个线程阻塞等待客户端请求 alt=旧I/O模型,多个线程阻塞等待客户端请求 src="http://www.flyoung.me/assets/images/javaio.jpg">Java NIOJava NIO不但引⼊了全新的⾼效的I/O机制,同时引⼊了基于Reactor设计模式的多路复⽤异步模式。
NIO包中主要包含以下⼏种抽象数据类型。
* Channel(通道):NIO把它⽀持的I/O对象抽象为Channel。
它模拟了通信连接,类似于原I/O中的流(Stream),⽤户可以通过它读取和写⼊数据。
⽬前已知的实例类有SocketChannel、ServerSocketChannel、DatagramChannel、 FileChannel等。
* Buffer(缓冲区):Buffer是⼀块连续的内存区域,⼀般作为Channel收发数据的载体出现。
java基础篇新I O技术(NIO) 电脑资料
java根底篇新I O技术(NIO) 电脑资料在JDK1.4以前,I/O输入输出处理,我们把它称为旧I/O处理,在JDK1.4开始,java提供了一系列改良的输入/输出新特性,这些功能被称为新I/O(NEW I/O),新添了许多用于处理输入/输出的类,这些类都被放在java.nio包及子包下,并且对原java.io包中的很多类以NIO为根底进行了改写,新添了满足新I/O的功能,Java NIO和IO的主要区别IONIO面向流面向缓冲阻塞IO非阻塞IO无选择器面向缓冲(Buffer)在整个Java的心I/O中,所以操作都是以缓冲区进行的,使操作的性能大大提高。
操作在Buffer中存在一系列的状态变量,这状态变量随着写入或读取都可能会被概念,在缓冲区开元使用是三个值表示缓冲区的状态。
position:表示下个缓冲区读取或写入的操作指针,没向缓冲区中华写入数据的时候此指针就会改变,指针永远放在写入的最后一个元素之后。
即:如果写入了4个位置的数据,那么posotion会指向第5个位置。
Limit:表示还有多少数据可以存储或读取,position<=limit capacity:表示缓冲区的最大容量,limit<=capacity,此值在分配缓冲区时被设置。
一般不改变。
创立缓冲区:import java.nio.IntBuffer ;public class IntBufferDemo{public static void main(String args[]){IntBuffer buf = IntBuffer.allocate(10) ; // 准备出10个大小的缓冲区System.out.print("1、写入数据之前的position、limit和capacity:") ;System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " + buf.capacity()) ;int temp[] = {5,7,9} ;// 定义一个int数组buf.put(3) ; // 设置一个数据buf.put(temp) ; // 此时已经存放了四个记录System.out.print("2、写入数据之后的position、limit和capacity:") ;System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " + buf.capacity()) ;buf.flip() ; // 重设缓冲区// postion = 0 ,limit = 原本positionSystem.out.print("3、准备输出数据时的position、limit和capacity:") ;System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " + buf.capacity()) ; System.out.print("缓冲区中的内容:") ;while(buf.hasRemaining()){int x = buf.get() ;System.out.print(x + "、") ;}}}如果创立了缓冲区,那么JVM可直接对其执行本机的IO操作import java.nio.ByteBuffer ;public class ByteBufferDemo{public static void main(String args[]){ByteBuffer buf = ByteBuffer.allocateDirect(10) ; // 准备出10个大小的缓冲区byte temp[] = {1,3,5,7,9} ; // 设置内容buf.put(temp) ; // 设置一组内容buf.flip() ;System.out.print("主缓冲区中的内容:") ;while(buf.hasRemaining()){int x = buf.get() ;System.out.print(x + "、") ;}}}通道(Channel)Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。
JavaNIO理解与使用
JavaNIO理解与使⽤Netty的使⽤或许我们看着官⽹user guide还是很容易⼊门的。
因为java nio使⽤⾮常的繁琐,netty对java nio进⾏了⼤量的封装。
对于Netty的理解,我们⾸先需要了解NIO的原理和使⽤。
所以,我也特别渴望去了解NIO这种通信模式。
官⽅的定义是:nio 是non-blocking的简称,在jdk1.4 ⾥提供的新api 。
Sun 官⽅标榜的特性如下:为所有的原始类型提供(Buffer)缓存⽀持。
字符集编码解码解决⽅案。
Channel :⼀个新的原始I/O 抽象。
⽀持锁和内存映射⽂件的⽂件访问接⼝。
提供多路(non-bloking) ⾮阻塞式的⾼伸缩性⽹络I/O 。
是不是很抽象?在阅读这篇技术⽂档之后,收获了很多。
包括对Java NIO的理解和使⽤,所以也特别的感谢作者。
⾸先,还是来回顾以下从这篇⽂档中学到的要点。
为什么要使⽤ NIO?NIO 的创建⽬的是为了让 Java 程序员可以实现⾼速 I/O ⽽⽆需编写⾃定义的本机代码。
NIO 将最耗时的 I/O 操作(即填充和提取缓冲区)转移回操作系统,因⽽可以极⼤地提⾼速度。
NIO最重要的组成部分通道 Channels缓冲区 Buffers选择器 SelectorsBuffer 是⼀个对象,它包含⼀些要写⼊或者刚读出的数据。
在 NIO 库中,所有数据都是⽤缓冲区处理的。
在读取数据时,它是直接读到缓冲区中的。
在写⼊数据时,它是写⼊到缓冲区中的。
任何时候访问 NIO 中的数据,您都是将它放到缓冲区中。
缓冲区实质上是⼀个数组。
通常它是⼀个字节数组,但是也可以使⽤其他种类的数组。
但是⼀个缓冲区不仅仅是⼀个数组。
缓冲区提供了对数据的结构化访问,⽽且还可以跟踪系统的读/写进程。
Channel是⼀个对象,可以通过它读取和写⼊数据看完下⾯这个例⼦,基本上就理解buffer和channel的作⽤了1. package yyf.java.nio.ibm;2.3. import java.io.*;4. import java.nio.*;5. import java.nio.channels.*;6.7. public class CopyFile {8. static public void main(String args[]) throws Exception {9.10. String infile = "c://test/nio_copy.txt";11. String outfile = "c://test/result.txt";12.13. FileInputStream fin = new FileInputStream(infile);14. FileOutputStream fout = new FileOutputStream(outfile);15. // 获取读的通道16. FileChannel fcin = fin.getChannel();17. // 获取写的通道18. FileChannel fcout = fout.getChannel();19. // 定义缓冲区,并指定⼤⼩20. ByteBuffer buffer = ByteBuffer.allocate(1024);21.22. while (true) {23. // 清空缓冲区24. buffer.clear();25. //从通道读取⼀个数据到缓冲区26. int r = fcin.read(buffer);27. //判断是否有从通道读到数据28. if (r == -1) {29. break;30. }31. //将buffer指针指向头部32. buffer.flip();33. //把缓冲区数据写⼊通道34. fcout.write(buffer);35. }36. }37. }缓冲区主要是三个变量positionlimitcapacity这三个变量⼀起可以跟踪缓冲区的状态和它所包含的数据。
JavaNIO编程(一)NIO入门
JavaNIO编程(⼀)NIO⼊门Java NIO 基本介绍Java NIO 全称 java non-blocking IO,是指 JDK 提供的新 API。
从 JDK1.4 开始,Java 提供了⼀系列改进的输⼊/输出的新特性,被统称为 NIO(即 New IO),是同步⾮阻塞的NIO 相关类都被放在 java.nio 包及⼦包下,并且对原 java.io 包中的很多类进⾏改写。
【基本案例】NIO 有三⼤核⼼部分:Channel(通道),Buffer(缓冲区), Selector(选择器)NIO是⾯向缓冲区,或者⾯向块编程的。
数据读取到⼀个它稍后处理的缓冲区,需要时可在缓冲区中前后移动,这就增加了处理过程中的灵活性,使⽤它可以提供⾮阻塞式的⾼伸缩性⽹络Java NIO的⾮阻塞模式,使⼀个线程从某通道发送请求或者读取数据,但是它仅能得到⽬前可⽤的数据,如果⽬前没有数据可⽤时,就什么都不会获取,⽽不是保持线程阻塞,所以直⾄数据变的可以读取之前,该线程可以继续做其他的事情。
⾮阻塞写也是如此,⼀个线程请求写⼊⼀些数据到某通道,但不需要等待它完全写⼊,这个线程同时可以去做别的事情。
通俗理解:NIO是可以做到⽤⼀个线程来处理多个操作的。
假设有10000个请求过来,根据实际情况,可以分配50或者100个线程来处理。
不像之前的阻塞IO那样,⾮得分配10000个。
HTTP2.0使⽤了多路复⽤的技术,做到同⼀个连接并发处理多个请求,⽽且并发请求的数量⽐HTTP1.1⼤了好⼏个数量级。
NIO 和 BIO 的⽐较BIO 以流的⽅式处理数据,⽽ NIO 以块的⽅式处理数据,块 I/O 的效率⽐流 I/O ⾼很多BIO 是阻塞的,NIO 则是⾮阻塞的BIO基于字节流和字符流进⾏操作,⽽ NIO 基于 Channel(通道)和 Buffer(缓冲区)进⾏操作,数据总是从通道读取到缓冲区中,或者从缓冲区写⼊到通道中。
Selector(选择器)⽤于监听多个通道的事件(⽐如:连接请求,数据到达等),因此使⽤单个线程就可以监听多个客户端通道NIO 三⼤核⼼类库简单介绍Selector 、 Channel 和 Buffer 的关系图每个 Channel 都会对应⼀个 Buffer,读写数据都要经过 BufferSelector 对应⼀个线程,⼀个线程可以对应多个 Channel(连接)该图反应了有三个 Channel 注册到该 Selector 多路复⽤器上Selector 会不断地轮询注册在其上地 Channel,如果某个Channel发送读或者写事件就会被轮询出来Buffer 就是⼀个内存块,底层是有⼀个数组,但 Buffer 不仅仅是⼀个数组,还提供了对数据的结构化访问以及维护读写位置等信息数据的读取写⼊是通过Buffer, 这个是和BIO 最⼤的区别, BIO 中要么是输⼊流,要么是输出流, 不能双向;但是NIO的 Buffer 是可以读也可以写, 只需要 flip ⽅法切换channel 是双向的, 可以返回底层操作系统的情况, ⽐如 Linux底层的操作系统通道就是双向的。
java基础之NIO介绍及使用
java基础之NIO介绍及使⽤⽬录⼀、NIO⼆、三⼤组件三、ByteBuffer的使⽤四、测试Demo五、Channel的使⽤六、⽹络编程七、Selector⼋、⽹络编程(多路复⽤)⼀、NIOjava.nio全称java non-blocking IO,是指jdk1.4 及以上版本⾥提供的新api(New IO),为所有的原始类型(boolean类型除外)提供缓存⽀持的数据容器,使⽤它可以提供⾮阻塞式的⾼伸缩性⽹络。
⼆、三⼤组件NIO三⼤组件:Channel、Buffer、Selector1.Channel 和BufferChannel是⼀个对象,可以通过它读取和写⼊数据。
拿 NIO 与原来的 I/O 做个⽐较,通道就像是流,⽽且他们⾯向缓冲区(Buffer)的。
所有数据都通过Buffer对象来处理,永远不会将字节直接写⼊通道中,⽽是将数据写⼊包含⼀个或多个字节的缓冲区。
也不会直接从通道中读取字节,⽽是将数据从通道读⼊缓冲区,再从缓冲区获取这个字节。
Channel是读写数据的双向通道,可以从Channel将数据读取Buffer,也可将Buffer的数据写⼊Channel,⽽之前的Stream要么是输⼊(InputStream)、要么是输出(OutputStream),只在⼀个⽅向上流通。
⽽通道(Channel)可以⽤于读、写或者同时⽤于读写常见的Channel1.FileChannel2.DatagramChannel3.SocketChannel4.ServerSocketChannelBuffer缓冲区⽤来读写数据,常见的Buffer1.ByteBuffer2.ShortBuffer3.IntBuffer4.LongBuffer5.FloatBuffer6.DoubleBuffer7.CharBuffer2.Selector在多线程模式下,阻塞IO时,⼀个线程只能处理⼀个请求,⽐如http请求,当请求响应式关闭连接,释放线程资源。
java nio
JAVA NIO一.Io与nio的区别标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
二.Nio核心组成:1.Channels(通道)(1)主要的channel实现有:SocketChannel、ServerSocketChannel、FileChannel、DatagramChannel;FileChannel:从FileChannel读取数据只需调用read()即可,在下面讲解buffer实例中已经讲解;向FileChannel中写入数据:SocketChannel:ServerSocketChannel:(2)scatter/gather(分散和聚集)分散(scatter)从Channel中读取是指在读操作时将读取的数据写入多个buffer中; 例:聚集(gather)写入Channel是指在写操作时将多个buffer的数据写入同一个Channel.例:2.Buffers(缓冲区)主要的buffer实现有:ShortBuffer、IntBuffer 、 LongBuffer、FloatBuffer 、DoubleBuffer 、CharBuffer 、 ByteBuffer。
使用Buffer读写数据一般遵循以下四个步骤:1.写入数据到Buffer2.调用flip()方法3.从Buffer中读取数据4.调用clear()方法或者compact()方法例:在这里我们一定着重理解一下Buffer的capacity,position和limit三个属性:Capacity:指定buffer大小值,例如上例:1024,一旦buffer满了,需要调用清除方法进行清除,才可以继续往里写数据。
Position:当前位置,初始值为0,最大值为capacity-1,当byte或long写入到buffer,会自动向前移动。
java中nio知识梳理及实例
java中nio知识梳理及实例最近,我学习了NITY的相关知识,涉及到NiO的相关知识,所以我梳理了NiO的基础。
1. 核⼼组件读写是JavaNIO中最基本的操作。
您可以创建缓冲区,从通道读取数据,同时将数据写⼊通道。
渠道缓冲区选择器在NiO中,我们使⽤通道和缓冲区。
NiO中的所有I/O都从⼀个通道开始。
数据总是从缓冲区写⼊通道,然后从通道读取到缓冲区2. 频道Java nio中的通道。
在通道包中,让我们看⼀下继承关系:2.1袜⼦通道Socketchannel⽤于TCP⽹络通信,以链接通道。
创建socketchannel有两种⽅法:当连接到达serversocketchannel时打开socketchannel并连接到服务让我们⽤选择器查看SoChanChanp客户端-服务器通信框架图:2.2 SocketChannel的操作打开SocketChannel:SocketChannel sc = SocketChannel.open();sc.connect(new InetSocketAddress("http://localhost", 8080));ByteBuffer bb = ByteBuffer.allocate(84);int bytesRead = sc.read(bb);String newData = "The new String is writing in a file ..." + System.currentTimeMillis();ByteBuffer bb= ByteBuffer.allocate(48);bb.clear();bb.put(newData.getBytes());bb.flip();while(bb.hasRemaining()) {sc.write(bb);}sc.close();3. Buffers下⾯看⼀下Buffer的继承关系选择器⽤于使⽤单个线程处理多个通道。
NIO原理解析
NIO原理解析Java NIO(New IO)是⼀个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO⼯作⽅式。
相关概念介绍:1)阻塞(Block)和⾮阻塞(Non-Block):关注的是线程或者进程在运⾏过程中是否等待调⽤结果的状态,多⽤于server端数据处理⽅式。
阻塞:程序运⾏过程中,当前线程或者进程在数据返回前会被操作系统挂起,只有等到返回数据后才继续执⾏(BIO模型)⾮阻塞:当前线程或者进程运⾏过程中,不管数据有没有准备好都不会被操作系统挂起⽽是直接继续执⾏其他⼯作。
2)同步(Synchronization)和异步(Asynchronous)的⽅式:关注的消息通信机制,相对于IO操作⽽⾔,⼤部分指client端调⽤时,对于结果返回是否等待:同步:调⽤者主动等待调⽤结果,在同⼀时间只能完成⼀个操作(JDK NIO模型)异步:调⽤者⽆需等待结果直接返回,被调⽤者通知调⽤者结果,在同⼀时间能够同时完成多个操作(JDK AIO模型)所以对于对于标准的IO属于同步阻塞⽅式,NIO属于同步⾮阻塞模式,AIO属于异步⾮阻塞模式。
BIO通信模型:在介绍NIO前先了解简单⼀下BIO,因为BIO是同步阻塞的,基本通信过程是每次client请求过来时server会启动⼀个线程进⾏通信,这种通信模型最⼤的缺点就是:⼀连接⼀线程的模型导致服务端⽆法承受⼤量客户端的并发连接。
以下时BIO的通信模型:NIO通信模型:对于NIO因为是同步⾮阻塞的,所以在事件处理模型上跟BIO有所不同,为了达到⾮阻塞⽬的采⽤⼀个线程来管理多个客户端的连接请求,这样能够确保在连接过程中不会被阻塞,在将建⽴好的连接分配给对应的处理线程。
在java NIO由⼏个核⼼部门组成:缓存Buffers;通道Channels;选择器Selectors。
缓冲区(buffer):本质上是⼀个数组,它包含⼀些要读写的数据,任何时候访问 NIO 数据,都是通过 Buffer 进⾏;通道(channel):是⼀个通道,通过它读写 Buffer 中的数据;多路复⽤器(selector):多路复⽤器,Selector 不断轮询注册在其上的 Channel,如果某个 Channel 有新的 TCP 链接接⼊、读和写事件,这个 Channel 就处于就绪状态,会被 Selector 轮组出来,然后通过SelectionKey() 可以获取就绪 Channel 的集合,进⾏后续的 IO⼀、缓存Buffers 缓冲区实际上是⼀个容器对象,更直接的说,其实就是⼀个数组,在NIO 库中,所有数据都是⽤缓冲区处理的。
JavaNIO入门学习(读写文件)
JavaNIO入门学习(读写文件)上一篇:Java NIO 入门学习(通道和缓冲区)我们用原有 IO 读写文件应该不会陌生了,顺带回顾一下,大致两种:1. 在 InputStream 或 OutputStream 上读写字节或字节数组,读InputStream 时用是否返回 -1 来判断是否到达末尾。
2. 包装成Reader/Writer 可以直接读写字符串,进一步包装到BufferedReader/BufferedWriter 就可以按行读写了。
readLine() 时看是否返回 null 断定是否读完了最后一行。
现在我们要用NIO 来读写文件,肯定是要用到Channel 和Buffer 了。
一句话描述过程就是从FileInputStream 得到的FileChannel 中读取数据到 Buffer 中,再处理 Buffer 中的数据。
看代码:上面程序使用了一个与文件尺寸等大的缓冲区,正好能一次性把文件内容全部读入内存,如果文件过多将是十分耗费的内存的,所以我们可能须手工指定某个大小(如1024,2048) 的缓冲区,然后分多次读入文件内容到缓冲区中。
这时候程序就是下面那样子了:同样的,如果是写入中文内容,也需要进行字符集的相关处理。
执行后在 C 盘根目录下产生 nio.tst 文件,内容就是 Hello, Java NIO。
此代码的关键之处就是对缓冲的 flip() 调用,你可以在调试模式下观察到 flip() 方法调用前后,缓冲区 bf 的 position/limit 属性的变化。
试着注释掉 flip() 代码,看看两次生成的 nio.tst 文件内容是不是大相径庭。
所以,要用好 NIO,缓冲区的 mark/position/limit/capacity 属性应理解,以及 clear()/flip()/rewind() 分别会怎么影响到以上属性。
还有,虽然说通道是双向的,字面上不像流那样区分输入通道或是输出通道,但实际通道也存在只读或只写的特性,例如由FileInputStream.getChannel() 获得的通道是无法写入内容的,由FileOutputStream.getChannel() 获得的通道是不能读的,否则会抛出相应的异常NonWritableChannelException 和NonReadableChannelException。
Java NIO2教程
Java NIO教程前言阅读本文前,建议你先了解旧I/ONIO 是New I/O 的缩写,要了解它真正的内涵,需要掌握的知识还是比较多的。
我努力在这几篇笔记里,勾勒出整个io的面貌。
为大家的深入学习铺路。
I/O简史想理解I/O的全部,java的I/O历史是必须要了解的。
java的I/O历史也从一个侧面反应了java的发展史。
JDK1.0-1.3在这个时期的java中,基本上可以说没有完整的I/O支持。
因为这一时期的java I/O操作是阻塞的,所以I/O效率是较为底下的,基本上想要有比较好的I/O解决方案,基本靠自己。
这时期java在服务器端一直没有得到重用,和糟糕的I/O效率是有很大的关系的。
不但I/O弄的不好,而且一系列周边措施都没弄好。
所支持的字符集编码有限,经常要进行手工的编码工作。
而且没有正则表达式,处理数据十分困难。
JDK1.4-1.62002年发布的java1.4中,非阻塞I/O以JSR-51的身份加入到java语言中。
同时字符集的编解码能力大大提升。
而且有了基于perl实现的正则表达式类库。
同时部分旧I/O底层实现,也用新I/O的方式重写,使得旧I/O的性能也有了提升。
终于java在服务器端开始流行了起来。
与此同时,第三方也开始发力。
谷歌发布了Guava类库,其中的I/O部分,极大的简化了一些文件的操作和数据的传输。
同时Trustin Lee领导编写的nio框架netty与mina也广为流传开来,这对java nio的发展业是有着极大的推动力的。
JDK1.7至今随着JSR-203的推出,是我们在java1.7中见到了NIO2。
它为我们提供了必非阻塞更加强大的异步I/O操作能力,同时提供了一系列极为方便的对文件系统和文件属性进行操作的API。
以及更加强大的网络I/OI/O区别阻塞I/O、非阻塞I/O、异步I/O之间到底有什么区别?为什么每一次的进步,都会促使java I/O 能力的极大提升?我们举一个种菜游戏的例子。
JAVANIO之浅谈内存映射文件原理与DirectMemory
JAVANIO之浅谈内存映射⽂件原理与DirectMemory类库中的NIO包相对于IO 包来说有⼀个新功能是内存映射⽂件,⽇常编程中并不是经常⽤到,但是在处理⼤⽂件时是⽐较理想的提⾼效率的⼿段。
本⽂我主要想结合中(OS)相关⽅⾯的知识介绍⼀下原理。
在传统的⽂件IO操作中,我们都是调⽤操作系统提供的底层标准IO系统调⽤函数 read()、write() ,此时调⽤此函数的进程(在JAVA中即java进程)由当前的⽤户态切换到内核态,然后OS的内核代码负责将相应的⽂件数据读取到内核的IO缓冲区,然后再把数据从内核IO缓冲区拷贝到进程的私有地址空间中去,这样便完成了⼀次IO操作。
⾄于为什么要多此⼀举搞⼀个内核IO缓冲区把原本只需⼀次拷贝数据的事情搞成需要2次数据拷贝呢?我想学过操作系统或者计算机系统结构的⼈都知道,这么做是为了减少磁盘的IO操作,为了提⾼性能⽽考虑的,因为我们的程序访问⼀般都带有局部性,也就是所谓的局部性原理,在这⾥主要是指的空间局部性,即我们访问了⽂件的某⼀段数据,那么接下去很可能还会访问接下去的⼀段数据,由于磁盘IO操作的速度⽐直接访问内存慢了好⼏个数量级,所以OS根据局部性原理会在⼀次read()系统调⽤过程中预读更多的⽂件数据缓存在内核IO缓冲区中,当继续访问的⽂件数据在缓冲区中时便直接拷贝数据到进程私有空间,避免了再次的低效率磁盘IO操作。
在JAVA中当我们采⽤IO包下的⽂件操作流,如:FileInputStream in = new FileInputStream("D:\\java.txt");in.read();JAVA虚拟机内部便会调⽤OS底层的 read()系统调⽤完成操作,如上所述,在第⼆次调⽤ in.read()的时候可能就是从内核缓冲区直接返回数据了(可能还有经过 native堆做⼀次中转,因为这些函数都被声明为 native,即本地平台相关,所以可能在C代码中有做⼀次中转,如win32中是通过 C代码从OS读取数据,然后再传给JVM内存)。
弄懂javabio和nio一篇就够!!!
弄懂javabio和nio⼀篇就够java I/OI/O模型前置知识1. 什么是同步与异步?2. 什么是阻塞与⾮阻塞?3. 什么是阻塞I/O与⾮阻塞I/O?4. 什么是同步I/O与异步I/O?什么是同步与异步?同步是指多个任务⼀起执⾏时,任务必须逐个完成,⼀个任务执⾏时会导致其他任务和整个流程的暂时等待。
异步是指多任务同时执⾏,不会导致其他任务或者整个流程处于暂停状态。
同步和异步的区别就是,执⾏多个任务时,⼀个任务的执⾏会不会导致其他任务的暂时暂停。
什么是阻塞与⾮阻塞?阻塞:当⼀个任务执⾏时且执⾏的条件不满⾜的时候会⼀直等待直到条件的满⾜。
⾮阻塞:当⼀个任务执⾏且条件不满⾜时会返回⼀个指⽰标志(告知条件不满⾜),⽽不是⼀直等待。
阻塞与⾮阻塞的区别就是:当⼀个任务执⾏且条件不满⾜时,是⼀直等待还是返回⼀个指⽰标志。
什么是阻塞I/O与⾮阻塞I/O?i/o操作分为两个步骤:1. 检查数据是否就绪2. 内核将数据拷贝到线程中阻塞I/O和⾮阻塞I/O区别就在第⼀步,阻塞I/O检查到数据未就绪就会⼀直等待知道数据准备就绪。
⽽⾮阻塞I/O遇到数据为就绪就返回⼀个指⽰标志,告诉线程数据没有准备就绪。
什么是同步I/O与异步I/O?同步I/O和异步I/O的区别就在于第⼆个步骤,同步I/O第⼆个步骤是线程完成的(会使当前线程阻塞,去完成I/O操作,把数据从内核拷贝到线程),⽽异步I/O第⼆个步骤是由内核完成的。
⼀个同步I/O操作会导致线程被阻塞,直到I/O操作完成。
⽽⼀个异步I/O操作不会导致发出请求的线程进⼊阻塞状态。
5种I/O模型阻塞I/O模型线程提出I/O请求之后,数据如果没有就绪那么线程就会交出CPU,进⼊阻塞状态,数据准备完毕后再将数据从内核态复制给线程,线程才进⼊就绪状态。
⾮阻塞I/O模型线程发出I/O请求之后,数据没有准备就绪,会返回⼀个指⽰标志发告诉线程数据没有准备就绪,但是线程不会交出CPU,⽽是不断地从⽤户带切换到内核状态,不断地询问数据是否准备就绪。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
JA V A NIO基础知识总结二(一)、回顾一下总结一:(1)、NIO的几个概念:①、Buffer :内存块,实质就是一个数组。
NIO数据读或写得中转地。
②、Channel:连接设备的通道。
用于向buffer提供数据或者读取数据,异步I/O支持。
③、Selector :channel事件的监听者,他能检测到一个或多个通道,并将事件分发出去④、SelectionKey:channel上发生的事件,包含了事件的状态信息和时间以及对应的channel。
(2)、在前面总结一中,最后的时候给出了一个完整的关于NIO操作网络套接字的例子,在这里先总结一下构建基于NIO的服务端的一般步骤:①、构造一个Selector②、打开一个serverSocketChannel③、设定serverSocketChannel为非阻塞④、绑定socketserverChannel到一个主机地址和端口⑤、注册selector并告知感兴趣的事情(3)、Channel的状态有四种:①、Connectable:当一个Channel完成socket连接操作已完成或者已失败。
②、Acceptable:当一个Channel已准备好接受一个新的socket连接时,channel是Acceptale③、Readable:当一个channel能被读时。
④、Writable:当一个Channel能被写时为可写状态。
(4)、下面是NIO中的关系图,来自于《java编程思想》(二)、基于多线程的NIO总结一的例子,是基于单线程的,单线程的好处是简单,不用去考虑过于复杂的线程问题,但是仔细想一下,如果数据在网络传输的过程中发生了阻塞呢,那岂不是要花费很多的时间?再者如果我们要实现像QQ中的聊天室呢,如何实现呢?。
为了解决这些问题,我们现在试着采用多线程的,但是采用多线程,会产生很多线程,创建、销毁线程都是要花费时间的,所以这里可以运用到线程池来管理。
下面一个例子是:客户端发来信息,服务端然后转发所有的信息给在线的客户端。
import java.io.IOException;import .InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.util.Iterator;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.logging.Level;import java.util.logging.Logger;public class RSocketServer implements Runnable {private final static int POOLSIZE = 100;// 处理线程池的大小private SelectionKey selectionKey; // 选择键private ExecutorService service =Executors.newFixedThreadPool(POOLSIZE);// 固定大小的线程池private boolean isRunning = true;private Selector selector;// 选择器private String writeMsg;// 需要写的信息private ServerSocketChannel ssc;public RSocketServer() {try {selector = Selector.open();ssc = ServerSocketChannel.open();ssc.configureBlocking(false);ssc.socket().bind(new InetSocketAddress(8080));selectionKey = ssc.register(selector,SelectionKey.OP_ACCEPT);System.out.println("服务器启动成功!正在端口为8080上等待...");} catch (Exception e) {e.printStackTrace();}}public void run() {try {while (isRunning) {int num = -1;try {// 监控注册在selector上的SelectableChannelnum = selector.select();} catch (IOException e) {e.printStackTrace();}if (num == 0) {continue;}Iterator<SelectionKey> it =selector.selectedKeys().iterator();while (it.hasNext()) {SelectionKey key = it.next();it.remove();if (!key.isValid())continue;if (key.isAcceptable()) {getConn(key);} else if (key.isReadable()) {System.out.println("可读");readMsg(key);}else if (key.isValid() && key.isWritable()) {if (writeMsg != null) {System.out.println("可写");RWriter(key);}}else break;}}Thread.yield();} catch (Exception e) {e.printStackTrace();}}private void getConn(SelectionKey key) throws IOException { ssc = (ServerSocketChannel) key.channel();SocketChannel sc = ssc.accept();sc.configureBlocking(false);sc.register(selector, SelectionKey.OP_READ);}private void readMsg(SelectionKey key) throws IOException {StringBuffer sb = new StringBuffer();SocketChannel sc = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);buffer.clear();int len = 0;while ((len = sc.read(buffer)) > 0) {buffer.flip();sb.append(new String(buffer.array(), 0, len));}if (sb.length() > 0)System.out.println("从客户端发来的数据:" + sb.toString());if ("exit".equals(sb.toString().trim())||sb.length()==0) { sc.write(ByteBuffer.wrap("bye".getBytes()));System.out.println("服务端已经关闭");key.cancel();sc.close();sc.socket().close();} else {String msg = sc.socket().getRemoteSocketAddress() + ":"+ sb.toString();Iterator<SelectionKey> it =key.selector().keys().iterator();// 把数据分发到每一个已经连接的客户端while (it.hasNext()) {SelectionKey skey = it.next();if (skey != key && skey != selectionKey) {RWriter myWriter = new RWriter(skey, msg);service.execute(myWriter);}}}}public static void main(String[] args) {RSocketServer server = new RSocketServer();new Thread(server).start();}class RWriter implements Runnable {SelectionKey key;String msg;public RWriter(SelectionKey key, String msg) {this.key = key;this.msg = msg;}public void run() {try {SocketChannel client = (SocketChannel) key.channel();client.write(ByteBuffer.wrap(msg.getBytes()));Thread.yield();} catch (IOException ex) {Logger.getLogger(RWriter.class.getName()).log(Level.SEVERE,null, ex);}}}private void RWriter(SelectionKey key) throws IOException { SocketChannel sc = (SocketChannel) key.channel();String str = (String) key.attachment();sc.write(ByteBuffer.wrap(str.getBytes()));key.interestOps(SelectionKey.OP_READ);}}(三)、Java NIO的Reactor模式看了上面的例子,有没有发觉一些问题呢?会不会觉得例子有点“乱七八糟”的感觉,接收数据、业务逻辑、发送数据、数据的包装等等,这些都需要我们去处理。