java nio的使用_Java NIO原理和使用

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

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

4f1150b881333f12a311ae9ef34da474.png原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。 面向流 的 I/O 系统一次一个字节地处

4f1150b881333f12a311ae9ef34da474.png理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。为流式数据创建过滤器非常容易。链接几个过滤器,以便每个过滤器只负责单个复杂处理机制的一部分,这样也是相对简单的。不利的一面是,面向流的 I/O 通常相当慢。 一个 面向块 的 I/O 系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的 I/O 缺少一些面向流的I/O 所具有的优雅性和简单性。

本文主要简单介绍NIO的基本原理,在下一篇文章中,将结合Reactor模式和著名线程大师Doug Lea的一篇文章深入讨论。

NIO主要原理和适用。

NIO 有一个主要的类Selector,这个类似一个观察者,只要我们把需要探知的socketchannel告诉Selector,我们接着做别的事情,当有事件发生时,他会通知我们,传回一组SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据,放心,包准能够读到,接着我们可以处理这些数据。

Selector内部原理实际是在做一个对所注册的channel的轮询访问,不断的轮询(目前就这一个算法),一旦轮询到一个channel有所注册的事情发生,比如数据来了,他就会站起来报告,交出一把钥匙,让我们通过这把钥匙来读取这个channel的内容。

首先简单的印象是NIO快,所以想写个程序验证一下.如下复制:

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifpublicstaticvoidtest2(String name1, String name2)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pnglongstart=System.currentTimeMillis();

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.giftry9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            FileInputStream fis=newFileInputStream(name1);

d18c02628675d0a2c816449d98bda930.png            FileOutputStream fos=newFileOutputStream(name2);

d18c02628675d0a2c816449d98bda930.pngbyte[] buf=newbyte[8129];

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifwhile(true)9b8a8a44dd1c74ae49c20a7cd451974e.png{                

d18c02628675d0a2c816449d98bda930.pngintn=fis.read(buf);

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(n==-1)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngbreak;

ecedf933ec37d714bd4c2545da43add2.png                 }d18c02628675d0a2c816449d98bda930.png                 fos.write(buf,0,n);

ecedf933ec37d714bd4c2545da43add2.png             }d18c02628675d0a2c816449d98bda930.png             fis.close();

d18c02628675d0a2c816449d98bda930.png            fos.close();

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif          }catch(Exception e)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.pnglongend=System.currentTimeMillis();

d18c02628675d0a2c816449d98bda930.pnglongtime=end-start;

d18c02628675d0a2c816449d98bda930.png        System.out.println(time);

8f1ba5b45633e9678d1db480c16cae3f.png     }4f1150b881333f12a311ae9ef34da474.png    

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifpublicstaticvoidtest3(String name1, String name2)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pnglongstart=System.currentTimeMillis();

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.giftry9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png             FileInputStream in=newFileInputStream(name1);

d18c02628675d0a2c816449d98bda930.png             FileOutputStream out=newFileOutputStream(name2);

d18c02628675d0a2c816449d98bda930.png            FileChannel fc1=in.getChannel();

d18c02628675d0a2c816449d98bda930.png            FileChannel fc2=out.getChannel();

d18c02628675d0a2c816449d98bda930.png            ByteBuffer bb=ByteBuffer.allocate(8129);

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifwhile(true)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                 bb.clear();

d18c02628675d0a2c816449d98bda930.pngintn=fc1.read(bb);

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(n==-1)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngbreak;

ecedf933ec37d714bd4c2545da43add2.png                }d18c02628675d0a2c816449d98bda930.png                 bb.flip();

d18c02628675d0a2c816449d98bda930.png                 fc2.write(bb);

ecedf933ec37d714bd4c2545da43add2.png             }d18c02628675d0a2c816449d98bda930.png             fc1.close();

d18c02628675d0a2c816449d98bda930.png            fc2.close();

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif          }catch(IOException e)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png  

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.pnglongend=System.currentTimeMillis();

d18c02628675d0a2c816449d98bda930.pnglongtime=end-start;

d18c02628675d0a2c816449d98bda930.png         System.out.println(time);

8f1ba5b45633e9678d1db480c16cae3f.png     }

本以为可以结束,结果测试结果出乎意料,函数一比函数二要快,就是说Old IO快于NIO ,从此也就开始了整个过程:

为了了解这个问题,仔细搜索并仔细再看IBM 的NIO教程,看到如下这段话

---------------------------------------------

在 JDK 1.4 中原来的 I/O 包和 NIO 已经很好地集成了。 java.io.* 已经以 NIO 为基础重新实现了,

所以现在它可以利用 NIO 的一些特性。例如, java.io.* 包中的一些类包含以块的形式读写数据的方法,

这使得即使在更面向流的系统中,处理速度也会更快。 也可以用 NIO 库实现标准 I/O 功能。例如,

可以容易地使用块 I/O 一次一个字节地移动数据。但是正如您会看到的,NIO 还提供了原 I/O 包中所没有的许多好处。

---------------------------------------------

了解了这个基本原理,我们结合代码看看使用,在使用上,也在分两个方向,一个是线程处理,一个是用非线程,后者比较简单,看下面代码:

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.*;

4f1150b881333f12a311ae9ef34da474.pngimportjava.nio.*;

4f1150b881333f12a311ae9ef34da474.pngimportjava.nio.channels.*;

4f1150b881333f12a311ae9ef34da474.pngimportjava.nio.channels.spi.*;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.*;

4f1150b881333f12a311ae9ef34da474.pngimportjava.util.*; 

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png*

d18c02628675d0a2c816449d98bda930.png*@authorAdministrator

d18c02628675d0a2c816449d98bda930.png*@version8f1ba5b45633e9678d1db480c16cae3f.png*/1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifpublicclassNBTest9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**Creates new NBTest*/d18c02628675d0a2c816449d98bda930.pngpublicNBTest()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

ecedf933ec37d714bd4c2545da43add2.png  }d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.pngpublicvoidstartServer()throwsException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngintchannels=0;

d18c02628675d0a2c816449d98bda930.pngintnKeys=0;

d18c02628675d0a2c816449d98bda930.pngintcurrentSelector=0;

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png//使用Selectord18c02628675d0a2c816449d98bda930.pngSelector selector=Selector.open();

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png//建立Channel 并绑定到9000端口d18c02628675d0a2c816449d98bda930.pngServerSocketChannel ssc=ServerSocketChannel.open();

d18c02628675d0a2c816449d98bda930.png  InetSocketAddress address=newInetSocketAddress(InetAddress.getLocalHost(),9000); 

d18c02628675d0a2c816449d98bda930.png  ssc.socket().bind(address);

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png//使设定non-blocking的方式。d18c02628675d0a2c816449d98bda930.pngssc.configureBlocking(false);

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png//向Selector注册Channel及我们有兴趣的事件d18c02628675d0a2c816449d98bda930.pngSelectionKey s=ssc.register(selector, SelectionKey.OP_ACCEPT);

d18c02628675d0a2c816449d98bda930.png  printKeyInfo(s);

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.pngwhile(true)//不断的轮询97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png    debug("NBTest: Starting select");

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png//Selector通过select方法通知我们我们感兴趣的事件发生了。d18c02628675d0a2c816449d98bda930.pngnKeys=selector.select();

d18c02628675d0a2c816449d98bda930.png//如果有我们注册的事情发生了,它的传回值就会大于0d18c02628675d0a2c816449d98bda930.pngif(nKeys>0)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png      debug("NBTest: Number of keys after select operation:"+nKeys);

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png//Selector传回一组SelectionKeys

d18c02628675d0a2c816449d98bda930.png//我们从这些key中的channel()方法中取得我们刚刚注册的channel。d18c02628675d0a2c816449d98bda930.pngSet selectedKeys=selector.selectedKeys();

d18c02628675d0a2c816449d98bda930.png      Iterator i=selectedKeys.iterator();

d18c02628675d0a2c816449d98bda930.pngwhile(i.hasNext())

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png         s=(SelectionKey) i.next();

d18c02628675d0a2c816449d98bda930.png         printKeyInfo(s);

d18c02628675d0a2c816449d98bda930.png         debug("NBTest: Nr Keys in selector:"+selector.keys().size());

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png//一个key被处理完成后,就都被从就绪关键字(ready keys)列表中除去d18c02628675d0a2c816449d98bda930.pngi.remove();

d18c02628675d0a2c816449d98bda930.pngif(s.isAcceptable())

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//从channel()中取得我们刚刚注册的channel。d18c02628675d0a2c816449d98bda930.pngSocket socket=((ServerSocketChannel)s.channel()).accept().socket();

d18c02628675d0a2c816449d98bda930.png           SocketChannel sc=socket.getChannel();

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png           sc.configureBlocking(false);

d18c02628675d0a2c816449d98bda930.png           sc.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);

d18c02628675d0a2c816449d98bda930.png                      System.out.println(++channels);

ecedf933ec37d714bd4c2545da43add2.png         }d18c02628675d0a2c816449d98bda930.pngelse97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png           debug("NBTest: Channel not acceptable");

ecedf933ec37d714bd4c2545da43add2.png         }ecedf933ec37d714bd4c2545da43add2.png      }ecedf933ec37d714bd4c2545da43add2.png   }d18c02628675d0a2c816449d98bda930.pngelse97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png      debug("NBTest: Select finished without any keys.");

ecedf933ec37d714bd4c2545da43add2.png   }d18c02628675d0a2c816449d98bda930.png

ecedf933ec37d714bd4c2545da43add2.png  }d18c02628675d0a2c816449d98bda930.png

ecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.pngprivatestaticvoiddebug(String s)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png  System.out.println(s);

ecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.pngprivatestaticvoidprintKeyInfo(SelectionKey sk)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png  String s=newString();

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png  s="Att:"+(sk.attachment()==null?"no":"yes");

d18c02628675d0a2c816449d98bda930.png  s+=", Read:"+sk.isReadable();

d18c02628675d0a2c816449d98bda930.png  s+=", Acpt:"+sk.isAcceptable();

d18c02628675d0a2c816449d98bda930.png  s+=", Cnct:"+sk.isConnectable();

d18c02628675d0a2c816449d98bda930.png  s+=", Wrt:"+sk.isWritable();

d18c02628675d0a2c816449d98bda930.png  s+=", Valid:"+sk.isValid();

d18c02628675d0a2c816449d98bda930.png  s+=", Ops:"+sk.interestOps();

d18c02628675d0a2c816449d98bda930.png  debug(s);

ecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png*@paramargs the command line arguments

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngpublicstaticvoidmain (String args[])

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png  NBTest nbTest=newNBTest();

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png    nbTest.startServer();

ecedf933ec37d714bd4c2545da43add2.png  }d18c02628675d0a2c816449d98bda930.pngcatch(Exception e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png    e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png  }ecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.png

8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.png

这是一个守候在端口9000的noblock server例子,如果我们编制一个客户端程序,就可以对它进行互动操作,或者使用telnet 主机名 90000 可以链接上。

通过仔细阅读这个例程,相信你已经大致了解NIO的原理和使用方法,下一篇,我们将使用多线程来处理这些数据,再搭建一个自己的Reactor模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值