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的主要区别
IO | NIO |
面向流 |
面向缓冲 |
阻塞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 = 原本position
System.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的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。
Java NIO的通道类似流,但又有些不同:
- 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。
- 通道可以异步地读写。
- 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。
正如上面所说,从通道读取数据到缓冲区,从缓冲区写入数据到通道。
Channel的实现
这些是Java NIO中最重要的通道的实现:
- FileChannel
- DatagramChannel
- SocketChannel
- ServerSocketChannel
FileChannel 从文件中读写数据。
DatagramChannel 能通过UDP读写网络中的数据。
SocketChannel 能通过TCP读写网络中的数据。
ServerSocketChannel可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
通过通道可以完成双向的输入和输出操作。在通道还有一种方式称为内存映射
几种读入的方式的比较
RandomAccessFile 较慢 FileInputStream 较慢 缓冲读取 速度较快
内存映射 速度最快
FileChannel内存映射实例
import java.nio.ByteBuffer ;
import java.nio.MappedByteBuffer ;
import java.nio.channels.FileChannel ;
import java.io.File ;
import java.io.FileOutputStream ;
import java.io.FileInputStream ;
public class FileChannelDemo03{
public static void main(String args[]) throws Exception{
File file = new File("d:" + File.separator + "oumyye.txt") ;
FileInputStream input = null ;
input = new FileInputStream(file) ;
FileChannel fin = null ; // 定义输入的通道
fin = input.getChannel() ; // 得到输入的通道
MappedByteBuffer mbb = null ;
mbb = fin.map(FileChannel.MapMode.READ_ONLY,0,file.length()) ;
byte data[] = new byte[(int)file.length()] ; // 开辟空间接收内容
int foot = 0 ;
while(mbb.hasRemaining()){
data[foot++] = mbb.get() ; // 读取数据
}
System.out.println(new String(data)) ; // 输出内容
fin.close() ;
input.close() ;
}
}
操作以上代码的时候,执行的是写入操作则可能是非常危险的,因为仅仅只是改变数组中的单个元素这种简单的操作,就可能直接修改磁盘上的文件,因为修改数据与数据保存在磁盘上是一样的。
选择器(Selectors)
Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。
为什么使用Selector?
仅用单个线程来处理多个Channels的好处是,只需要更少的线程来处理通道。事实上,可以只用一个线程处理所有的通道。对于操作系统来说,线程之间上下文切换的开销很大,而且每个线程都要占用系统的一些资源(如内存)。因此,使用的线程越少越好。
但是,需要记住,现代的操作系统和CPU在多任务方面表现的越来越好,所以多线程的开销随着时间的推移,变得越来越小了。实际上,如果一个CPU有多个内核,不使用多任务可能是在浪费CPU能力。不管怎么说,关于那种设计的讨论应该放在另一篇不同的文章中。在这里,只要知道使用Selector能够处理多个通道就足够了。
要点
使用Selector可以构建一个非阻塞的网络服务。
在新IO实现网络程序需要依靠ServerSocketChannel类与SocketChannel
Selector实例
下面使用Selector完成一个简单的服务器的操作,服务器可以同时在多个端口进行监听,此服务器的主要功能是返回当前时间。
import java.net.InetSocketAddress ;
import java.net.ServerSocket ;
import java.util.Set ;
import java.util.Iterator ;
import java.util.Date ;
import java.nio.channels.ServerSocketChannel ;
import java.nio.ByteBuffer ;
import java.nio.channels.SocketChannel ;
import java.nio.channels.Selector ;
import java.nio.channels.SelectionKey ;
public class DateServer{
public static void main(String args[]) throws Exception {
int ports[] = {8000,8001,8002,8003,8005,8006} ; // 表示五个监听端口
Selector selector = Selector.open() ; // 通过open()方法找到Selector
for(int i=0;i<ports.length;i++){
ServerSocketChannel initSer = null ;
initSer = ServerSocketChannel.open() ; // 打开服务器的通道
initSer.configureBlocking(false) ; // 服务器配置为非阻塞
ServerSocket initSock = initSer.socket() ;
InetSocketAddress address = null ;
address = new InetSocketAddress(ports[i]) ; // 实例化绑定地址
initSock.bind(address) ; // 进行服务的绑定
initSer.register(selector,SelectionKey.OP_ACCEPT) ; // 等待连接
System.out.println("服务器运行,在" + ports[i] + "端口监听。") ;
}
// 要接收全部生成的key,并通过连接进行判断是否获取客户端的输出
int keysAdd = 0 ;
while((keysAdd=selector.select())>0){ // 选择一组键,并且相应的通道已经准备就绪
Set<SelectionKey> selectedKeys = selector.selectedKeys() ;// 取出全部生成的key
Iterator<SelectionKey> iter = selectedKeys.iterator() ;
while(iter.hasNext()){
SelectionKey key = iter.next() ; // 取出每一个key
if(key.isAcceptable()){
ServerSocketChannel server = (ServerSocketChannel)key.channel() ;
SocketChannel client = server.accept() ; // 接收新连接
client.configureBlocking(false) ;// 配置为非阻塞
ByteBuffer outBuf = ByteBuffer.allocateDirect(1024) ; //
outBuf.put(("当前的时间为:" + new Date()).getBytes()) ; // 向缓冲区中设置内容
outBuf.flip() ;
client.write(outBuf) ; // 输出内容
client.close() ; // 关闭
}
}
selectedKeys.clear() ; // 清楚全部的key
} }
}
服务器完成之后可以使用Telnet命令完成,这样就完成了一个一部的操作服务器。
java基础篇---新I/O技术(NIO)的更多相关文章
- java基础篇---I/O技术
java基础篇---I/O技术 对于任何程序设计语言而言,输入输出(I/O)系统都是比较复杂的而且还是比较核心的.在java.io.包中提供了相关的API. java中流的概念划分 流的方向: 输 ...
- java基础篇---I/O技术(三)
接上一篇java基础篇---I/O技术(二) Java对象的序列化和反序列化 什么叫对象的序列化和反序列化 要想完成对象的输入或输出,还必须依靠对象输出流(ObjectOutputStream)和对象 ...
- 小白—职场之Java基础篇
java基础篇 java基础 目录 1.java是一种什么语言,jdk,jre,jvm三者的区别 2.java 1.5之后的三大版本 3.java跨平台及其原理 4.java 语言的特点 5.什么是字 ...
- Java基础篇 - 强引用、弱引用、软引用和虚引用
Java基础篇 - 强引用.弱引用.软引用和虚引用 原创零壹技术栈 最后发布于2018-09-09 08:58:21 阅读数 4936 收藏展开前言Java执行GC判断对象是否存活有两种方式其中一种是 ...
- 金三银四跳槽季,BAT美团滴滴java面试大纲(带答案版)之一:Java基础篇
Java基础篇: 题记:本系列文章,会尽量模拟面试现场对话情景, 用口语而非书面语 ,采用问答形式来展现.另外每一个问题都附上“延伸”,这部分内容是帮助小伙伴们更深的理解一些底层细节的补充,在面试中可 ...
- JAVA基础(10)——IO、NIO
转载:http://blog.csdn.net/weitry/article/details/52964948 JAVA基础系列规划: JAVA基础(1)——基本概念 JAVA基础(2)——数据类型 ...
- Java基础篇(JVM)——类加载机制
这是Java基础篇(JVM)的第二篇文章,紧接着上一篇字节码详解,这篇我们来详解Java的类加载机制,也就是如何把字节码代表的类信息加载进入内存中. 我们知道,不管是根据类新建对象,还是直接使用类变量 ...
- java基础篇---HTTP协议
java基础篇---HTTP协议 HTTP协议一直是自己的薄弱点,也没抽太多时间去看这方面的内容,今天兴致来了就在网上搜了下关于http协议,发现有园友写了一篇非常好的博文,博文地址:(http: ...
- Java基础-反射(reflect)技术详解
Java基础-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类加载器 1>.JVM 类加载机制 如下图所示,JVM类加载机制分为五个部分 ...
随机推荐
- linux arm的高端内存映射
linux arm的高端内存映射(1) vmalloc 高端内存映射 与高端映射对立的是低端映射或所谓直接映射,内核中有关变量定义它们的它们的分界点,全局变量high_memory,该变量定义在m ...
- process credentials(三)
主要内容包括: 1.进程描述符中Realtime Mutex相关数据结构的初始化 2.子进程如何复制父进程的credentials 3.per-task delay accounting的处理 4.子 ...
- selenium webdriver如何拿到页面的加载时间
这个问题与语言无关,对于现代浏览器来说,使用 window.performance.timing这个对象就好了. 用execute_script方法(java用executeScript)方法执行 w ...
- git经常使用命令和问题
和远程仓库相关的命令: 下载仓库代码:git clone 远程仓库地址 查看远程仓库:git remote -v 加入远程仓库:git remote add origin [url], 当中origi ...
- Android 获取自带浏览器上网记录
先是搜索了一下,在manifest里添加 <uses-permission android:name="com.android.browser.permission.READ_HIST ...
- 王勇详谈 Linux Deepin 背后的故事
(Linux Deepin最近发布了12.12版本.其也许是国内第一款比较优秀的桌面Linux系统.在此向致力于研发国产OS系统的猿人们表示敬意.虽然Deepin只是基于Ubuntu在桌面应用和UI方 ...
- nodejs 遍历文件夹下所有的图片改名为中文
安装依赖 $ npm init -y && npm i fs-extra globby request -S main.js const fs = require('node-fs-e ...
- ubuntu14安装redis
1.下载源文件 wget http://download.redis.io/releases/redis-3.0.7.tar.gz 2.解压 tar vxzf redis-3.0.7.tar.gz 3 ...
- MySQL积累
从csv文件写入mysql表:从/root/failure.csv读取数据写入表d_disk_failure,每行中的每个项用逗号分割,每个项只取用"包含的内容,如果没有"则取全部 ...
- 关系型数据库性能测试参考指标----SQL Server
注:以下指标取自SQL Server自身提供的性能计数器. [@more@] SQL Server 指标名称 指标描述 指标范围 指标单位 1.SQL Server中访问方法(Access Metho ...