摘自:http://blog.csdn.net/tsyj810883979/article/details/6876603

1.1  非阻塞模式

Java  NIO非堵塞应用通常适用用在I/O读写等方面,我们知道,系统运行的性能瓶颈通常在I/O读写,包括对端口和文件的操作上,过去,在打开一个I/O通道后,read()将一直等待在端口一边读取字节内容,如果没有内容进来,read()也是傻傻的等,这会影响我们程序继续做其他事情,那么改进做法就是开设线程,让线程去等待,但是这样做也是相当耗费资源(传统socket通讯服务器设计模式)的。

  Java NIO非堵塞技术实际是采取Reactor模式,或者说是Observer模式为我们监察I/O端口,如果有内容进来,会自动通知我们,这样,我们就不必开启多个线程死等,从外界看,实现了流畅的I/O读写,不堵塞了。

  Java NIO出现不只是一个技术性能的提高,你会发现网络上到处在介绍它,因为它具有里程碑意义,从JDK1.4开始,Java开始提高性能相关的功能,从而使得Java在底层或者并行分布式计算等操作上已经可以和C或Perl等语言并驾齐驱。

  如果你至今还是在怀疑Java的性能,说明你的思想和观念已经完全落伍了,Java一两年就应该用新的名词来定义。从JDK1.5开始又要提供关于线程、并发等新性能的支持,Java应用在游戏等适时领域方面的机会已经成熟,Java在稳定自己中间件地位后,开始蚕食传统C的领域。

NIO 有一个主要的类Selector,这个类似一个观察者,只要我们把需要探知的socketchannel告诉Selector,我们接着做别的事情,当有事件发生时,他会通知我们,传回一组  SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据,放心,包准能够读到,接着我们可以处理这些数据。  Selector内部原理实际是在做一个对所注册的channel的轮询访问,不断的轮询(目前就这一个算法),一旦轮询到一个channel有所注册的事情发生,比如数据来了,他就会站起来报告,交出一把钥匙,让我们通过这把钥匙(SelectionKey表示SelectableChannel在Selector中的注册的标记)来读取这个channel的内容。

实现一:使用nio实现文件复制

  1. package study.nio;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.FileNotFoundException;
  6. import java.io.IOException;
  7. import java.nio.channels.FileChannel;
  8. import java.nio.ByteBuffer;
  9. public class TestCopyFile {
  10. public static void main(String[] args) throws IOException {
  11. //调用FileManager类的copyFile静态方法
  12. FileManager.copyFile(new File("src.txt"), new File("dst.txt"));
  13. }
  14. }
  15. class FileManager {
  16. //把可能出现的异常抛给上层调用者处理
  17. public static void copyFile(File src, File dst)
  18. throws FileNotFoundException, IOException {
  19. //得到一个源文件对应的输入通道
  20. FileChannel fcin = new FileInputStream(src).getChannel();
  21. //得到一个目标文件对应的输出通道
  22. FileChannel fcout = new FileOutputStream(dst).getChannel();
  23. //生成一个1024字节的ByteBuffer实例
  24. ByteBuffer buf = ByteBuffer.allocate(1024);
  25. while(fcin.read(buf) != -1) {
  26. buf.flip();     //准备写
  27. fcout.write(buf);
  28. buf.clear();        //准备读
  29. }
  30. }
  31. }

还可以使用下面方式进行操作,在FileChannel中有两个特殊方法可以允许我们直接将两个通道相连:

long transferFrom(ReadableByteChannel src, long position, long count);

long transferTo(long position, long count, WriteableByteChannel targets);

上面while循环可以替换为:

fcin.transferTo(0, fcin.size(), fcout); 或者 fcout.transferFrom(fcin, 0, fcin.size());

实现二:向一个空文件中写入some text,再以只读方式打开该文件,在尾部追加some more,最终将该文件内容输出。

  1. package study.nio;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.RandomAccessFile;
  6. import java.nio.ByteBuffer;
  7. import java.nio.channels.FileChannel;
  8. public class GetChannel {
  9. //为了使代码明晰,暂不处理异常
  10. public static void main(String[] args) throws Exception {
  11. FileChannel fc = null;
  12. //向一个文件中写入文本
  13. fc = new FileOutputStream(new File("data.txt")).getChannel();
  14. fc.write(ByteBuffer.wrap("some text".getBytes()));
  15. fc.close();
  16. //以读写方式打开文件,并在尾部追加内容
  17. fc = new RandomAccessFile("data.txt", "rw").getChannel();
  18. fc.position(fc.size());
  19. fc.write(ByteBuffer.wrap("some more".getBytes()));
  20. fc.close();
  21. //将文件里的内容读出来
  22. fc = new FileInputStream("data.txt").getChannel();
  23. ByteBuffer buf = ByteBuffer.allocate(1024);
  24. fc.read(buf);
  25. buf.flip();
  26. while(buf.hasRemaining()) {
  27. System.out.print((char)buf.get());
  28. }
  29. }
  30. }

以上均使用的是字节操作流,与nio相一致。Reader和Writer这些字符模式类不能用于产生通道,但是java.nio.channels.Channels类中提供了实用方法,可以在通道中产生Reader和Writer。  Channels.newReader();  Channels.newWriter();

实现三:将一个大文件映射到内存并查找指定的文本内容是否在该文件中(曾记得李开复与微软的故事,当然李开复是从邮件中查找信息,并且邮件被截成了图片,⊙﹏⊙b汗)

  1. public class LargeMappedFiles {
  2. public static void main(String args[]) {
  3. try {
  4. File[] files = new File[] {new File("src1.txt"), new File("src2.txt")};
  5. ArrayList<String> ls = search(files, "something is wrong");
  6. for(int i=0; i<ls.size(); i++) {
  7. System.out.println(ls.get(i));
  8. }
  9. } catch (FileNotFoundException e) {
  10. e.printStackTrace();
  11. } catch (Exception e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. //实现简单的内容检索
  16. private static ArrayList<String> search(File[] files, String text) throws Exception {
  17. //把检索结果放到一个list中
  18. ArrayList<String> result = new ArrayList<String>();
  19. //循环遍历文件
  20. for(File src : files) {
  21. //将整个文件映射到内存
  22. MappedByteBuffer dst = new RandomAccessFile(src, "rw")
  23. .getChannel()
  24. .map(FileChannel.MapMode.READ_WRITE, 0, src.length());
  25. //对字符进行解码
  26. String str = Charset.forName("UTF-8").decode(dst).toString();
  27. //准备进行读
  28. dst.flip();
  29. if(str.indexOf(text) != -1) {
  30. result.add(src.getName());
  31. }
  32. //准备写
  33. dst.clear();
  34. }
  35. return result;
  36. }
  37. }

实现四:在前面的学习中了解到nio为所有原始数据类型提供了Buffer支持,并且在ByteBuffer中实现了asXBuffer()方法直接将一个ByteBuffer转换成其它类型的Buffer。本例实现数据类型的转换。

  1. import java.nio.IntBuffer;
  2. import java.nio.FloatBuffer;
  3. import java.nio.ByteBuffer;
  4. import java.util.Arrays;
  5. public class CastBuffer {
  6. static byte[] bytes = new byte[] {0, 1, 2, 3, 4, 5, 'a', 'b', 'c'};
  7. public static void main(String[] args) {
  8. ByteBuffer bBuf = ByteBuffer.wrap(bytes);
  9. System.out.println(Arrays.toString(bBuf.array()));
  10. //转换成IntBuffer
  11. IntBuffer iBuf = ((ByteBuffer)bBuf.rewind()).asIntBuffer();
  12. while(iBuf.hasRemaining()) {
  13. System.out.print(iBuf.get()+",");
  14. }
  15. //转换成FloatBuffer
  16. FloatBuffer fBuf = ((ByteBuffer)bBuf.rewind()).asFloatBuffer();
  17. while(fBuf.hasRemaining()) {
  18. System.out.print(fBuf.get()+",");
  19. }
  20. }
  21. }

其它类型转换与上面方法类似,各种方法都相似。

NIO Channel的学习笔记总结的更多相关文章

  1. Java NIO 学习笔记(一)----概述,Channel/Buffer

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  2. Java NIO 完全学习笔记(转)

    本篇博客依照 Java NIO Tutorial翻译,算是学习 Java NIO 的一个读书笔记.建议大家可以去阅读原文,相信你肯定会受益良多. 1. Java NIO Tutorial Java N ...

  3. Java NIO 核心组件学习笔记

    背景知识 同步.异步.阻塞.非阻塞 首先,这几个概念非常容易搞混淆,但NIO中又有涉及,所以总结一下[1]. 同步:API调用返回时调用者就知道操作的结果如何了(实际读取/写入了多少字节). 异步:相 ...

  4. Java NIO学习笔记

    Java NIO学习笔记 一 基本概念 IO 是主存和外部设备 ( 硬盘.终端和网络等 ) 拷贝数据的过程. IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成. 所有语言运行时系统提供执 ...

  5. Java NIO 学习笔记(七)----NIO/IO 的对比和总结

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  6. Java NIO 学习笔记(六)----异步文件通道 AsynchronousFileChannel

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  7. Java NIO 学习笔记(五)----路径、文件和管道 Path/Files/Pipe

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  8. Java NIO 学习笔记(四)----文件通道和网络通道

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  9. Java NIO 学习笔记(三)----Selector

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

随机推荐

  1. (十三)maven之release和snapshots

    发布release 用户A将代码打包到RELEASE仓库.用户B使用时,需要在pom.xml添加jar包的依赖坐标.如果用户A将jar包版本从1.0升级到2.0,用户B使用时也需要在pom.xml中修 ...

  2. dp 20190618

    C. Party Lemonade 这个题目是贪心,开始我以为是背包,不过也不太好背包,因为这个L都已经是1e9了. 这个题目怎么贪心呢?它是因为这里有一个二倍的关系,所以说val[i]=val[i- ...

  3. 爬虫4_python2

    import urllib2 response = urllib2.urlopen("https://www.baidu.com") print response.read() 构 ...

  4. 使用bat脚本调用py文件直接获取应用的包名和targetversion

    背景: 在上一篇已经介绍过如何利用python调用aapt获取包名 https://www.cnblogs.com/reseelei-despair/p/11078750.html 但是因为每次都要修 ...

  5. shell脚本,计算创建100个文件所用多少时间。

    [root@localhost mulu]# ls [root@localhost mulu]# `; do touch file$i; done real 0m0.104s user 0m0.012 ...

  6. 不安装oracle客户端用sqlplus连接数据库

    在不安装oracle客户端情况下用sqlplus连接数据库: 1.去官网下载 http://www.oracle.com/technetwork/topics/winx64soft-089540.ht ...

  7. ios之自定义导航栏上的返回按钮

    导航栏的按钮,右边的按钮是可以自己随意添加的.但左边的返回按钮怎么定制?你会说,添加一个自己的按钮呗!你可以试试看,这样行不行. 正确的答案是重载UINavigationController类的pus ...

  8. Windows平台下使用vs code搭建python3环境(1)

    前言:最近几周在使用python开发的过程中,碰到了好多坑,由于以前使用visual studio 2015习惯了,导致刚开始搭建python开发环境以及管理各种包的时候有点不习惯,再加上python ...

  9. LeetCode 最长连续递增序列

    给定一个未经排序的整数数组,找到最长且连续的的递增序列. 示例 1: 输入: [1,3,5,4,7] 输出: 3 解释: 最长连续递增序列是 [1,3,5], 长度为3. 尽管 [1,3,5,7] 也 ...

  10. 简单的Redis数据迁移

    dump迁移 1.安装redis-dump工具 sudo apt-get install ruby rubygems ruby-devel -y gem sources --add http://ge ...