BIO和NIO

BIO在之前的服务器处理模型中,在调用ServerSocket.accept()方法时,会一直阻塞到有客户端连接才会返回,每个客户端连接过来后,服务端都会accept一个新连接,接着启动一个线程去处理该客户端的请求。在这个新的线程中,也会在read()方法中阻塞,直到读取完数据,处理完成后销毁该处理线程。

这样会有什么问题呢?

当客户端并发访问增加后,服务端线程个数膨胀,频繁出现由于IO阻塞导致挂起的线程,系统性能将急剧下降,容易发生线程堆栈溢出、创建新线程失败等问题。

阻塞导致大量线程资源被浪费;阻塞可导致大量的上下文切换,很多切换其实是无意义的

Java自1.4以后,加入了新IO特性NIO,NIO带来了non-blocking特性。

那么NIO是如何帮助我们解决这种问题的呢(反应器设计模式)?

1). 由一个专门的线程来处理所有的 IO 事件,并负责分发。 
2). 事件驱动机制:事件到的时候触发,而不是同步的去监视事件。 
3). 线程通讯:线程之间通过 wait,notify 等方式通讯。保证每次上下文切换都是有意义的。减少无谓的线程切换。

服务端和客户端各自维护一个管理通道的对象,我们称之为selector,该对象能检测一个或多个通道 (channel) 上的事件。我们以服务端为例,如果服务端的selector上注册了读事件,某时刻客户端给服务端发送了一些数据,NIO的服务端会在selector中添加一个读事件。服务端的处理线程会轮询地访问selector,如果访问selector时发现有感兴趣的事件到达,则处理这些事件,如果没有感兴趣的事件到达,则处理线程会一直阻塞直到感兴趣的事件到达为止。

1、IO的例子

/* 字节IO */
public void byteIO() throws FileNotFoundException, IOException {
FileInputStream fin = new FileInputStream(new File(
"D:\\test\\byteio_in.txt"));
FileOutputStream fout = new FileOutputStream(new File(
"D:\\test\\byteio_out.txt"));
int c = -1;
while ((c = fin.read()) != -1) {
fout.write(c);
}
fin.close();
fout.close();
} /* 字符IO */
public void charIO() throws FileNotFoundException, IOException {
FileReader reader = new FileReader(new File("D:\\test\\chario_in.txt",
""));
FileWriter writer = new FileWriter(new File("D:\\test\\chario_out.txt"));
char[] charArr = new char[512];
while (reader.read(charArr) != -1) {
writer.write(charArr);
}
reader.close();
writer.close();
} /* bufferIO */
public void bufferIO() throws FileNotFoundException, IOException {
BufferedInputStream bufferReader = new BufferedInputStream(
new FileInputStream("D:\\test\\bufferio_in.txt"));
BufferedOutputStream bufferWriter = new BufferedOutputStream(
new FileOutputStream("D:\\test\\bufferio_out.txt"));
int c = -1;
while ((c = bufferReader.read()) != -1) {
bufferWriter.write(c);
}
bufferReader.close();
bufferWriter.close();
}

2、NIO的例子

/* NIO */
public void NIO() throws FileNotFoundException, IOException {
FileInputStream fin = new FileInputStream("D:\\test\\nio_in.txt");
FileOutputStream fout = new FileOutputStream("D:\\test\\nio_out.txt");
FileChannel finChannel = fin.getChannel();
FileChannel foutChannel = fout.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(512);
while (finChannel.read(buffer) != 1)//读到缓存
{
buffer.flip();//指针跳到缓存头
foutChannel.write(buffer);
buffer.clear();//重置缓冲区
}
fin.close();
fout.close();
}

3、NIO实现非阻塞Server服务

下面是一个NIO实现Server的例子

public class MultiPortEcho {
private int ports[];
private ByteBuffer echoBuffer = ByteBuffer.allocate(1024); public MultiPortEcho(int ports[]) throws IOException {
this.ports = ports;
go();
} private void go() throws IOException {
// Create a new selector
Selector selector = Selector.open(); // Open a listener on each port, and register each one with the selector
for (int i = 0; i < ports.length; ++i) {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ServerSocket ss = ssc.socket();
InetSocketAddress address = new InetSocketAddress(ports[i]);
ss.bind(address);
SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Going to listen on " + ports[i]);
} while (true) {
int num = selector.select();
Set selectedKeys = selector.selectedKeys();
Iterator it = selectedKeys.iterator(); while (it.hasNext()) {
SelectionKey key = (SelectionKey) it.next(); if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
// Accept the new connection
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false); // Add the new connection to the selector
SelectionKey newKey = sc.register(selector,SelectionKey.OP_READ);
it.remove(); System.out.println("Got connection from " + sc);
} else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
// Read the data
SocketChannel sc = (SocketChannel) key.channel(); // Echo data
int bytesEchoed = 0;
while (true) {
echoBuffer.clear();
int r = sc.read(echoBuffer);
if (r <= 0) {
break;
}
echoBuffer.flip();
sc.write(echoBuffer);
bytesEchoed += r;
} System.out.println("Echoed " + bytesEchoed + " from " + sc);
it.remove();
} }
}
} static public void main(String args[]) throws Exception { int ports[] = {1234,6765,7987}; for (int i = 0; i < args.length; ++i) {
ports[i] = Integer.parseInt(args[i]);
} new MultiPortEcho(ports);
}
}

参考资料:

http://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html#ibm-pcon

http://weixiaolu.iteye.com/blog/1479656

JavaIO和JavaNIO的更多相关文章

  1. Linux IO 概念(2)【转】

    转自:https://www.cnblogs.com/qq289736032/p/9188455.html 在上一篇IO底层的概念中杂合了很多模糊的概念,受知识水平的限制,只是从网上抄了很多过来.从l ...

  2. Linux IO 概念(2)

    在上一篇IO底层的概念中杂合了很多模糊的概念,受知识水平的限制,只是从网上抄了很多过来.从linux一切皆文件的设计哲学,介绍了文件描述符,从进程的运行内存分配,进程的切换,介绍了进程的阻塞,以及引出 ...

  3. JavaIO学习笔记(五)

    JavaIO前期准备 什么是同步 指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪 什么是异步 异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO ...

  4. javaIO系统----再看装饰者模式

    javaIO系统拥有各种各样的类,尤其是每次要进行读写操作时,总会一层套一层的new,以前不明白为什么要这样做,不过学习了适配器模式后,对于这种做法立刻了解了:动态扩展IO的功能,使之符合使用者的习惯 ...

  5. Java学习日记之 Java-IO流

    Java中的IO流在处理上分为字节流和字符流.字节流和字符流的区别 : 1.字节流读取的时候,读到一个字节就返回一个字节:  字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,在UTF-8 ...

  6. javaIO框架小析

    IO即数据读写.数据是应用的中心要素,而数据读写的能力和可扩展性是编程平台的基础支撑. 概念框架 方式: 字节流 Byte 和 字符流 Char 方向: 输入 Input 和 输出 Output : ...

  7. javaNIO(转载)

    (一) Java NIO 概述 Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然Java NIO 中除此之外还有很多类和组件,但在我看来,Chan ...

  8. javaIO流实现读写txt文件

    javaIO流实现文件读写 文件写入: InputStreamReader BufferedReader 文件读取: FileOutputStream package javatest.basic22 ...

  9. JAVANIO通道

    package com.nio.test; import java.io.FileInputStream; import java.io.FileNotFoundException; import j ...

随机推荐

  1. gamework的使用方法

    翻译来源地址:https://github.com/Kadoba/gamework gamework是控制LOVE2D游戏进程流的一个项目. ↑ 这个是按原文译的, 当初乍看完全不懂, 接下来我来用图 ...

  2. Lua读写文件

    文件读写 文件读写对制作游戏很有帮助.可以调用别的文件中的代码,保存最高分.游戏存档.玩家状态等信写到文件中. 首先,让我们看一个简单的命令:dofile.这个命令会读入另一个文件的代码并立即执行. ...

  3. Diagram of Spring 3.0 module dependencies--转载

    原文地址:http://www.ogrigas.eu/spring/2009/12/diagram-of-spring-3-0-module-dependencies As Spring 3.0.0. ...

  4. mysql记录sql执行时间

    1.开启和关闭mysql> set profiling=1;mysql> set profiling=0; information_schema 的 database 会建立一个PROFI ...

  5. 控件WebView网页的加载

    Android:控件WebView网页的加载 WebView可以使得网页轻松的内嵌到app里,还可以直接跟js相互调用. webview有两个方法:setWebChromeClient 和 setWe ...

  6. 对《[Unity官方实例教程 秘密行动] Unity官方教程《秘密行动》(十二) 角色移动》的一些笔记和个人补充,解决角色在地形上移动时穿透问题。

    这里素材全是网上找的. 教程看这里: [Unity官方实例教程 秘密行动] Unity官方教程<秘密行动>(九) 角色初始设定 一.模型设置: 1.首先设置模型的动作无限循环. 不设置的话 ...

  7. JavaScript工厂模式代码

    function createPerson(name,age,job){ var o=new Object(); o.name=name; o.age=age; o.job=job; o.sayNam ...

  8. iOS 导航栏颜色字体等的自定义

    1.设置导航栏中间文字的文字颜色和文字大小 方法一:系统方法 self.title = @"下载微课";//在有navigationController的控制器中,作用与self. ...

  9. 关于automatic_Panoramic_Image_Stitching_using_Invariant_features 的阅读笔记(2)

    接上一篇: http://www.cnblogs.com/letben/p/5446074.html#3538201 捆绑调整 (好开心有同学一起来看看这些问题,要不然就是我自己的话,我应该也不会看的 ...

  10. state/ui-router

    state/ui-router 一个状态对应于一个页面位置 通过定义controller.template和view等属性,来定义指定位置的用户界面和界面行为 通过嵌套的方式来解决页面中的一些重复出现 ...