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. jodd-StringTemplateParser使用

    StringTemplateParser 时一个string模板的解析器.在string模板中定义类似jsp标签的宏. 在解析过程中,宏被对值替换,值通过自定义的MacroResolver解析得到. ...

  2. ClamAV

    ClamAV 简介以及适用范围 ClamAV是一个在命令行下查毒软件,因为它不将杀毒作为主要功能,默认只能查出您计算机内的病毒,但是无法清除,至多删除文件.ClamAV可以工作很多的平台上,但是有少数 ...

  3. SecureCRT 滚动条设置

    不久前在Debian下使用kermit时发现kermit有一些优点,比如当串口上不断有信息打印时,仍然可以通过拖动滚动条来查看以前打印的信息,并且滚动条不会滚动到最下面.当按下回车键时,滚动条会自动滚 ...

  4. Linux Shell之top命令

    TOP是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行该命令,它将独占前台,直到用户终止该程序为止.比较准确的说,top命令提供了实时的对系统处理器的状态监视.它将显示系统中C ...

  5. 我的Blog开张啦,欢迎大家赏脸

        Blog开张,以后会慢慢更新工作.学习遇到的问题,总结一些经验,观众老爷们多多支持!!!  ^_^

  6. iOS企业级开发者计划的申请流程

    第一步:访问苹果企业版iDP网址:https://developer.apple.com/programs/ios/enterprise/点击Apply Now按钮,开始申请流程. 第二步:点击App ...

  7. C#.net 获取当前应用程序所在路径及环境变量

    一.获取当前文件的路径 string str1=Process.GetCurrentProcess().MainModule.FileName;//可获得当前执行的exe的文件名. string st ...

  8. 转 如何使用velocity模板引擎开发网站

    基于 Java 的网站开发,很多人都采用 JSP 作为前端网页制作的技术,尤其在是国内.这种技术通常有一些问题,我试想一下我们是怎样开发网站的,通常有几种方法: 1:功能确定后,由美工设计网页的UI( ...

  9. 下拉选择框加listview删除

    package com.downselect; import java.util.ArrayList; import android.R.array; import android.app.Activ ...

  10. [Javascript]jquery $(document).ready() 与window.onload的区别

    引用:http://www.jb51.net/article/21628.htm Jquery中$(document).ready()的作用类似于传统JavaScript中的window.onload ...