您的位置:

javanio,javanio和io的区别

本文目录一览:

java nio 开发实例

首先了解下所谓的java nio是个什么东西!

传统的并发型服务器设计是利用阻塞型网络I/O 以多线程的模式来实现的 然而由

于系统常常在进行网络读写时处于阻塞状态 会大大影响系统的性能 自Java 开始引入

了NIO(新I/O) API 通过使用非阻塞型I/O 实现流畅的网络读写操作 为开发高性能并发

型服务器程序提供了一个很好的解决方案 这就是java nio

首先来看下传统的阻塞型网络 I/O的不足

Java 平台传统的I/O 系统都是基于Byte(字节)和Stream(数据流)的 相应的I/O 操

作都是阻塞型的 所以服务器程序也采用阻塞型I/O 进行数据的读 写操作 本文以TCP

长连接模式来讨论并发型服务器的相关设计 为了实现服务器程序的并发性要求 系统由一

个单独的主线程来监听用户发起的连接请求 一直处于阻塞状态 当有用户连接请求到来时

程序都会启一个新的线程来统一处理用户数据的读 写操作

这种模式的优点是简单 实用 易管理 然而缺点也是显而易见的 由于是为每一个客

户端分配一个线程来处理输入 输出数据 其线程与客户机的比例近似为 随着线程

数量的不断增加 服务器启动了大量的并发线程 会大大加大系统对线程的管理开销 这将

成为吞吐量瓶颈的主要原因 其次由于底层的I/O 操作采用的同步模式 I/O 操作的阻塞管

理粒度是以服务于请求的线程为单位的 有可能大量的线程会闲置 处于盲等状态 造成I/O

资源利用率不高 影响整个系统的性能

对于并发型服务器 系统用在阻塞型I/O 等待和线程间切换的时间远远多于CPU 在内

存中处理数据的时间 因此传统的阻塞型I/O 已经成为制约系统性能的瓶颈 Java 版本

后推出的NIO 工具包 提供了非阻塞型I/O 的异步输入输出机制 为提高系统的性能提供

了可实现的基础机制

NIO 包及工作原理

针对传统I/O 工作模式的不足 NIO 工具包提出了基于Buffer(缓冲区) Channel(通

道) Selector(选择器)的新模式 Selector(选择器) 可选择的Channel(通道)和

SelectionKey(选择键)配合起来使用 可以实现并发的非阻塞型I/O 能力

NIO 工具包的成员

Buffer(缓冲器)

Buffer 类是一个抽象类 它有 个子类分别对应于七种基本的数据类型 ByteBuffer

CharBuffer DoubleBuffer FloatBuffer IntBuffer LongBuffer 和ShortBuffer 每一个Buffer

对象相当于一个数据容器 可以把它看作内存中的一个大的数组 用来存储和提取所有基本

类型(boolean 型除外)的数据 Buffer 类的核心是一块内存区 可以直接对其执行与内存有关

的操作 利用操作系统特性和能力提高和改善Java 传统I/O 的性能

Channel(通道)

Channel 被认为是NIO 工具包的一大创新点 是(Buffer)缓冲器和I/O 服务之间的通道

具有双向性 既可以读入也可以写出 可以更高效的传递数据 我们这里主要讨论

ServerSocketChannel 和SocketChannel 它们都继承了SelectableChannel 是可选择的通道

分别可以工作在同步和异步两种方式下(这里的可选择不是指可以选择两种工作方式 而是

指可以有选择的注册自己感兴趣的事件) 当通道工作在同步方式时 它的功能和编程方法

与传统的ServerSocket Socket 对象相似 当通道工作在异步工作方式时 进行输入输出处

理不必等到输入输出完毕才返回 并且可以将其感兴趣的(如 接受操作 连接操作 读出

操作 写入操作)事件注册到Selector 对象上 与Selector 对象协同工作可以更有效率的支

持和管理并发的网络套接字连接

Selector(选择器)和SelectionKey(选择键)

各类 Buffer 是数据的容器对象 各类Channel 实现在各类Buffer 与各类I/O 服务间传输

数据 Selector 是实现并发型非阻塞I/O 的核心 各种可选择的通道将其感兴趣的事件注册

到Selector 对象上 Selector 在一个循环中不断轮循监视这各些注册在其上的Socket 通道

SelectionKey 类则封装了SelectableChannel 对象在Selector 中的注册信息 当Selector 监测

到在某个注册的SelectableChannel 上发生了感兴趣的事件时 自动激活产生一个SelectionKey

对象 在这个对象中记录了哪一个SelectableChannel 上发生了哪种事件 通过对被激活的

SelectionKey 的分析 外界可以知道每个SelectableChannel 发生的具体事件类型 进行相应的

处理

NIO 工作原理

通过上面的讨论 我们可以看出在并发型服务器程序中使用NIO 实际上是通过网络事

件驱动模型实现的 我们应用Select 机制 不用为每一个客户端连接新启线程处理 而是将

其注册到特定的Selector 对象上 这就可以在单线程中利用Selector 对象管理大量并发的网

络连接 更好的利用了系统资源 采用非阻塞I/O 的通信方式 不要求阻塞等待I/O 操作完

成即可返回 从而减少了管理I/O 连接导致的系统开销 大幅度提高了系统性能

当有读或写等任何注册的事件发生时 可以从Selector 中获得相应的

SelectionKey 从SelectionKey 中可以找到发生的事件和该事件所发生的具体的

SelectableChannel 以获得客户端发送过来的数据 由于在非阻塞网络I/O 中采用了事件触

发机制 处理程序可以得到系统的主动通知 从而可以实现底层网络I/O 无阻塞 流畅地读

写 而不像在原来的阻塞模式下处理程序需要不断循环等待 使用NIO 可以编写出性能更

好 更易扩展的并发型服务器程序

并发型服务器程序的实现代码

应用 NIO 工具包 基于非阻塞网络I/O 设计的并发型服务器程序与以往基于阻塞I/O 的

实现程序有很大不同 在使用非阻塞网络I/O 的情况下 程序读取数据和写入数据的时机不

是由程序员控制的 而是Selector 决定的 下面便给出基于非阻塞网络I/O 的并发型服务器

程序的核心代码片段

import java io * //引入Java io包

import * //引入包

import java nio channels * //引入Java nio channels包

import java util * //引入Java util包

public class TestServer implements Runnable

{

/**

* 服务器Channel对象 负责接受用户连接

*/

private ServerSocketChannel server

/**

* Selector对象 负责监控所有的连接到服务器的网络事件的发生

*/

private Selector selector

/**

* 总的活动连接数

*/

private int activeSockets

/**

* 服务器Channel绑定的端口号

*/

private int port

/**

*

* 构造函数

*/

public TestServer()throws IOException

{

activeSockets=

port= //初始化服务器Channel绑定的端口号为

selector= Selector open() //初始化Selector对象

server=ServerSocketChannel open() //初始化服务器Channel对象

ServerSocket socket=server socket() //获取服务器Channel对应的//ServerSocket对象

socket bind(new InetSocketAddress(port)) //把Socket绑定到监听端口 上

nfigureBlocking(false) //将服务器Channel设置为非阻塞模式

server register(selector SelectionKey OP_ACCEPT) //将服务器Channel注册到

Selector对象 并指出服务器Channel所感兴趣的事件为可接受请求操作

}

public void run()

{

while(true)

{

try

{

/**

*应用Select机制轮循是否有用户感兴趣的新的网络事件发生 当没有

* 新的网络事件发生时 此方法会阻塞 直到有新的网络事件发生为止

*/

selector select()

}

catch(IOException e)

{

continue //当有异常发生时 继续进行循环操作

}

/**

* 得到活动的网络连接选择键的集合

*/

SetSelectionKey keys=selector selectedKeys()

activeSockets=keys size() //获取活动连接的数目

if(activeSockets== )

{

continue //如果连接数为 则继续进行循环操作

}

/**

/**

* 应用For—Each循环遍历整个选择键集合

*/

for(SelectionKey key :keys)

{

/**

* 如果关键字状态是为可接受 则接受连接 注册通道 以接受更多的*

事件 进行相关的服务器程序处理

*/

if(key isAcceptable())

{

doServerSocketEvent(key)

continue

}

/**

* 如果关键字状态为可读 则说明Channel是一个客户端的连接通道

* 进行相应的读取客户端数据的操作

*/

if(key isReadable())

{

doClientReadEvent(key)

continue

}

/**

* 如果关键字状态为可写 则也说明Channel是一个客户端的连接通道

* 进行相应的向客户端写数据的操作

*/

if(key isWritable())

{

doClinetWriteEvent(key)

continue

}

}

}

}

/**

* 处理服务器事件操作

* @param key 服务器选择键对象

*/

private void doServerSocketEvent(SelectionKey key)

{

SocketChannel client=null

try

{

ServerSocketChannel server=(ServerSocketChannel)key channel()

client=server accept()

if(client==null)

{

return

}

nfigureBlocking(false) //将客户端Channel设置为非阻塞型

/**

/**

* 将客户端Channel注册到Selector对象上 并且指出客户端Channel所感

* 兴趣的事件为可读和可写

*/

client register(selector SelectionKey OP_READ|SelectionKey OP_READ)

}catch(IOException e)

{

try

{

client close()

}catch(IOException e ){}

}

}

/**

* 进行向客户端写数据操作

* @param key 客户端选择键对象

*/

private void doClinetWriteEvent(SelectionKey key)

{

代码实现略

}

/**

* 进行读取客户短数据操作

* @param key 客户端选择键对象

*/

private void doClientReadEvent(SelectionKey key)

{

代码实现略

}

}

从上面对代码可以看出 使用非阻塞性I/O进行并发型服务器程序设计分三个部分

向Selector对象注册感兴趣的事件 从Selector中获取所感兴趣的事件 根据不同的事件进

行相应的处理

结语

通过使用NIO 工具包进行并发型服务器程序设计 一个或者很少几个Socket 线程就可

以处理成千上万个活动的Socket 连接 大大降低了服务器端程序的开销 同时网络I/O 采取

非阻塞模式 线程不再在读或写时阻塞 操作系统可以更流畅的读写数据并可以更有效地向

CPU 传递数据进行处理 以便更有效地提高系统的性能

看到这里相信你看了不止 分钟了吧   我说 分钟其实就是想让大家能够轻松的读下去(鸡蛋 )

好了 到这里大家应该对java nio有个初步的了解了吧~~~

lishixinzhi/Article/program/Java/hx/201311/27190

Java中IO与NIO的区别和使用场景

在java2以前,传统的socket IO中,需要为每个连接创建一个线程,当并发的连接数量非常巨大时,线程所占用的栈内存和CPU线程切换的开销将非常巨大。java5以后使用NIO,不再需要为每个线程创建单独的线程,可以用一个含有限数量线程的线程池,甚至一个线程来为任意数量的连接服务。由于线程数量小于连接数量,所以每个线程进行IO操作时就不能阻塞,如果阻塞的话,有些连接就得不到处理,NIO提供了这种非阻塞的能力。

NIO 设计背后的基石:反应器模式,用于事件多路分离和分派的体系结构模式。

反应器(Reactor):用于事件多路分离和分派的体系结构模式

通常的,对一个文件描述符指定的文件或设备, 有两种工作方式: 阻塞 与非阻塞 。所谓阻塞方式的意思是指, 当试图对该文件描述符进行读写时, 如果当时没有东西可读,或者暂时不可写, 程序就进入等待 状态, 直到有东西可读或者可写为止。而对于非阻塞状态, 如果没有东西可读, 或者不可写, 读写函数马上返回, 而不会等待 。

一种常用做法是:每建立一个Socket连接时,同时创建一个新线程对该Socket进行单独通信(采用阻塞的方式通信)。这种方式具有很高的响应速度,并且控制起来也很简单,在连接数较少的时候非常有效,但是如果对每一个连接都产生一个线程的无疑是对系统资源的一种浪费,如果连接数较多将会出现资源不足的情况。

另一种较高效的做法是:服务器端保存一个Socket连接列表,然后对这个列表进行轮询,如果发现某个Socket端口上有数据可读时(读就绪),则调用该socket连接的相应读操作;如果发现某个 Socket端口上有数据可写时(写就绪),则调用该socket连接的相应写操作;如果某个端口的Socket连接已经中断,则调用相应的析构方法关闭该端口。这样能充分利用服务器资源,效率得到了很大提高。

传统的阻塞式IO,每个连接必须要开一个线程来处理,并且没处理完线程不能退出。

非阻塞式IO,由于基于反应器模式,用于事件多路分离和分派的体系结构模式,所以可以利用线程池来处理。事件来了就处理,处理完了就把线程归还。而传统阻塞方式不能使用线程池来处理,假设当前有10000个连接,非阻塞方式可能用1000个线程的线程池就搞定了,而传统阻塞方式就需要开10000个来处理。如果连接数较多将会出现资源不足的情况。非阻塞的核心优势就在这里。

为什么会这样,下面就对他们做进一步细致具体的分析:

首先,我们来分析传统阻塞式IO的瓶颈在哪里。在连接数不多的情况下,传统IO编写容易方便使用。但是随着连接数的增多,问题传统IO就不行了。因为前面说过,传统IO处理每个连接都要消耗一个线程,而程序的效率当线程数不多时是随着线程数的增加而增加,但是到一定的数量之后,是随着线程数的增加而减少。这里我们得出结论,传统阻塞式IO的瓶颈在于不能处理过多的连接。

然后,非阻塞式IO的出现的目的就是为了解决这个瓶颈。而非阻塞式IO是怎么实现的呢?非阻塞IO处理连接的线程数和连接数没有联系,也就是说处理 10000个连接非阻塞IO不需要10000个线程,你可以用1000个也可以用2000个线程来处理。因为非阻塞IO处理连接是异步的。当某个链接发送请求到服务器,服务器把这个连接请求当作一个请求"事件",并把这个"事件"分配给相应的函数处理。我们可以把这个处理函数放到线程中去执行,执行完就把线程归还。这样一个线程就可以异步的处理多个事件。而阻塞式IO的线程的大部分时间都浪费在等待请求上了。

所谓阻塞式IO流,就是指在从数据流当中读写数据的的时候,阻塞当前线程,直到IO流可以

重新使用为止,你也可以使用流的avaliableBytes()函数看看当前流当中有多少字节可以读取,这样

就不会再阻塞了。

介绍一下Java NIO,NIO读取文件都有哪些方法

NIO也就是New I/O,是一组扩展Java IO操作的API集, 于Java 1.4起被引入,Java 7中NIO又提供了一些新的文件系统API,叫NIO2.

NIO2提供两种主要的文件读取方法:

使用buffer和channel类

使用Path 和 File 类

NIO读取文件有以下三种方式:

1. 旧的NIO方式,使用BufferedReader

import java.io.BufferedReader;

import java.io.FileReader;

import java.io.IOException;

public class WithoutNIOExample

{

public static void main(String[] args)

{

BufferedReader br = null;

String sCurrentLine = null;

try

{

br = new BufferedReader(

new FileReader("test.txt"));

while ((sCurrentLine = br.readLine()) != null)

{

System.out.println(sCurrentLine);

}

}

catch (IOException e)

{

e.printStackTrace();

}

finally

{

try

{

if (br != null)

br.close();

} catch (IOException ex)

{

ex.printStackTrace();

}

}

}

}

2. 使用buffer读取小文件

import java.io.IOException;

import java.io.RandomAccessFile;

import java.nio.ByteBuffer;

import java.nio.channels.FileChannel;

public class ReadFileWithFileSizeBuffer

{

public static void main(String args[])

{

try

{

RandomAccessFile aFile = new RandomAccessFile(

"test.txt","r");

FileChannel inChannel = aFile.getChannel();

long fileSize = inChannel.size();

ByteBuffer buffer = ByteBuffer.allocate((int) fileSize);

inChannel.read(buffer);

buffer.rewind();

buffer.flip();

for (int i = 0; i fileSize; i++)

{

System.out.print((char) buffer.get());

}

inChannel.close();

aFile.close();

}

catch (IOException exc)

{

System.out.println(exc);

System.exit(1);

}

}

}

3. 分块读取大文件

import java.io.IOException;

import java.io.RandomAccessFile;

import java.nio.ByteBuffer;

import java.nio.channels.FileChannel;

public class ReadFileWithFixedSizeBuffer

{

public static void main(String[] args) throws IOException

{

RandomAccessFile aFile = new RandomAccessFile

("test.txt", "r");

FileChannel inChannel = aFile.getChannel();

ByteBuffer buffer = ByteBuffer.allocate(1024);

while(inChannel.read(buffer) 0)

{

buffer.flip();

for (int i = 0; i buffer.limit(); i++)

{

System.out.print((char) buffer.get());

}

buffer.clear(); // do something with the data and clear/compact it.

}

inChannel.close();

aFile.close();

}

}

4. 使用MappedByteBuffer读取文件

import java.io.RandomAccessFile;

import java.nio.MappedByteBuffer;

import java.nio.channels.FileChannel;

public class ReadFileWithMappedByteBuffer

{

public static void main(String[] args) throws IOException

{

RandomAccessFile aFile = new RandomAccessFile

("test.txt", "r");

FileChannel inChannel = aFile.getChannel();

MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());

buffer.load();?

for (int i = 0; i buffer.limit(); i++)

{

System.out.print((char) buffer.get());

}

buffer.clear(); // do something with the data and clear/compact it.

inChannel.close();

aFile.close();

}

}

Java NIO和IO的区别

Java

NIO和IO的主要区别如下:

1.NIO

的创建目的是为了让

Java

程序员可以实现高速

I/O

而无需编写自定义的本机代码。NIO

将最耗时的

I/O

操作(即填充和提取缓冲区)转移回操作系统,因而可以极大地提高速度。传统的IO操作属于阻塞型,严重影响程序的运行速度。

2,。流与块的比较。原来的

I/O

库(在

java.io.*中)

NIO

最重要的区别是数据打包和传输的方式。正如前面提到的,原来的

I/O

以流的方式处理数据,而

NIO

以块的方式处理数据。

面向流

I/O

系统一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。为流式数据创建过滤器非常容易。链接几个过滤器,以便每个过滤器只负责单个复杂处理机制的一部分,这样也是相对简单的。不利的一面是,面向流的

I/O

通常相当慢。

3.一个

面向块

I/O

系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的

I/O

缺少一些面向流的

I/O

所具有的优雅性和简单性。