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. AJAX全套

    AJAX概述 AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术. AJAX = 异步 Java ...

  2. js技巧总结

    很早以前看到的代码,同时加上一些我在项目中用到的代码,感觉很实用,在这里记录下来,怕忘记了,有些代码忘记在哪看到的了,所以就不贴网址了,感谢各位大神的分享!如果有其他的好的方法,欢迎留言~ 1.取整的 ...

  3. Debian 8 安装 Nvidia 显卡驱动

    sudo apt-get install linux-headers-$(uname -r|sed 's,[^-]*-[^-]*-,,') nvidia-kernel-dkms 正在读取软件包列表.. ...

  4. javaScript入门2--变量,作用域,内存

    变量类型:基本类型和引用类型 基本类型上节已经提到.基本类型的值是按值传递的,既改变形参的值不会影响实参 <html> <head> <meta charset=&quo ...

  5. LRU在MySQL缓存池的实现

    MySQL的InnoDB引擎设置有索引及数据缓存池,其中用到的LRU算法来维持缓存的命中率 这里用到了顺序表list来作为缓冲池,每个数据节点称为block 该算法采用“中点插入法”:当插入一个新bl ...

  6. JQuery总结:选择器归纳、DOM遍历和事件处理、DOM完全操作和动画 (转)

    JQuery总结:选择器归纳.DOM遍历和事件处理.DOM完全操作和动画 转至元数据结尾 我们后台可能用到的页面一般都是用jquery取值赋值的,发现一片不错的文章 目录 JQuery总结一:选择器归 ...

  7. spring--mybatis事务总结

    spring--事务原理.mybatis--MapperScannerConfigurer 和 mybatis--MapperProxy事务,最近想把spring mybatis中的事务和mapper ...

  8. Gulp 自动化的项目构建工具

    在很多场合都会听到前端工和 node 程师推荐 Grunt 来实现项目的自动化,自动化可以自动完成 javascript/coffee/sass/less 等文件的的测试.检查.合并.压缩.格式化.部 ...

  9. 转:Android官方MVP架构示例项目解析

    转自: http://www.infoq.com/cn/articles/android-official-mvp-architecture-sample-project-analysis 作者 吕英 ...

  10. Sharepoint 2013 系列篇(安装部署)--上篇

    前言 sharepoint的部署是按照物理拓扑图的架构来部署,按照物理拓扑图架构分为一层拓扑图架构,二层拓扑图架构,三层拓扑图架构,多层拓扑图架构. 按照分层的拓扑图部署是按照需求来划分的,一层拓扑图 ...