非阻塞I/O–Java NIO教程

转载请标明:http://blog.geekcome.com/archives/261

Java NIO核心组件:

  • channels
  • Buffers
  • Selectors

虽然NIO还有其他的组件,上面的三个是核心。

Channel

基本上,所以的IO在NIO中都是从一个Channel开始。Channel有点像流(Stream),数据可以从Channel读取到Buufer,也可以从Buffer写到Channel。Channel有下面的几种类型:

  • FileChannel(文件IO)
  • DatagramChannel(UDP数据报IO)
  • SocketChannel(TCP数据报IO)
  • ServerSocketChannel(监听新进来的TCP链接)

Channel和流的区别:

  • Channel可以是双向的,流一般是单向的
  • Channel可以异步的读写
  • Channel总是需要Buffuer来读写数据

ServerSocketChannel:

1 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
2 serverSocketChannel.socket().bind(new InetSocketAddress(9999));
3 while(true){
4     SocketChannel socketChannel =
5             serverSocketChannel.accept();
6     //do something with socketChannel...
7 }

ServerSocketChannel:

1 socketChannel.configureBlocking(false);
2 socketChannel.connect(new InetSocketAddress("http://jenkov.com"80));
3  
4 while(! socketChannel.finishConnect() ){
5     //wait, or do something else...
6 }

Buffer

NIO中Buffer的类型:

  • ByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer
  • Mappeddyteuffer

这些Buffer覆盖了你能通过IO发送的数据基本类型,顾名思义。

使用Buffer的四个步骤:

  • 写入数据到Buffer
  • 调用flip()函数
  • 从Buffer中读取数据
  • 调用clear()函数
01 RandomAccessFile aFile = new RandomAccessFile("/home/yan/pci1","rw");
02         FileChannel channel = aFile.getChannel();
03  
04         ByteBuffer buf = ByteBuffer.allocate(20);
05  
06         int res = channel.read(buf);
07         while(res != -1){
08             buf.flip();
09             while(buf.hasRemaining()){
10                 System.out.println((char)buf.getChar());
11             }
12             buf.clear();
13  
14             res = channel.read(buf);
15         }

Buffer还支持多个Buffer组成缓冲数组,对其进程读写操作。

Selector

非阻塞I/O–Java NIO教程

Selector允许单线程处理多个Channel(一个Channel就是一个连接),如果每个连接的流量都很小,使用Selector就会很方便,如上图所示。而不用每个Channel来新建一个线程处理。

要使用Selector,首先要进程注册,想selector注册Channel,然后调用selector的select方法。这个方法会阻塞到某个注册的事件就绪,一旦这个方法返回,线程就可以处理这些事件。

创建Selector

调用Selector.open()方法来创建一个Selector:

1 Selector selector = Selector.open()

像Selector注册通道:

1 channel.configureBloacking(false);
2 SelectionKey key = channel.register(selector,SeletionKey.OP_READ);

SelectionKey

SelectionKey对象中含有如下属性:

  • interest集合(使用&操作SelectionKey.OP_ACCEPT和key.interestOps())
  • ready集合(key.readyOps(),可以使用&操作检测该集合,也可以使用is方法)
  • Channel(key.channel())
  • Selector(key.selector())
  • 附加对象(key.attach(obj)   Object obj = key.attachment())

selector通道选择

  • int select()//阻塞
  • int select(long timeout)//超时之前阻塞
  • int selectNow()//不阻塞

selectedKeys()

一单调用select方法并且返回了,说明有一个或多个通道就绪了,然后通过该方法选择已经就绪的集合,然后遍历这些集合对每个通道进行处理。

01 Set selectedKeys = selector.selectedKeys();
02 Iterator keyIterator = selectedKeys.iterator();
03 while(keyIterator.hasNext()) {
04     SelectionKey key = keyIterator.next();
05     if(key.isAcceptable()) {
06         // a connection was accepted by a ServerSocketChannel.
07     else if (key.isConnectable()) {
08         // a connection was established with a remote server.
09     else if (key.isReadable()) {
10         // a channel is ready for reading
11     else if (key.isWritable()) {
12         // a channel is ready for writing
13     }
14     keyIterator.remove();
15 }


参考文章:http://tutorials.jenkov.com/java-nio/overview.html

非阻塞I/O–Java NIO教程,布布扣,bubuko.com

非阻塞I/O–Java NIO教程

上一篇:算法 - 求子数组的最大和(C++)


下一篇:java HashMap 实现原理探究