Java NIO总结

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java NIO总结相关的知识,希望对你有一定的参考价值。

一、NIO

NIO是new IO,也是非阻塞IO。有Channel、Selector、Buffer、Pipe、FileLock等类。

Buffer在java.nio包

Channel、Selector、Pipe、FileLock等在java.nio.channels包

 

二、Channel通道

设置非阻塞configureBlocking(false);

注册选择器register(selector,SelectionKey.OP_XXX)

使用方法read(Buffer) ,write(Buffer)

使用方法open()获取Channel

  • FileChannel       使用FileInputStream,FileOutputStream,RandomAccessFile或者open(Path path, OpenOption... options)可以获取channel对象
  • ServerSocketChannel
  • SocketChannel
  • DatagramChannel
  • Pipe.SinkChannel         使用pipe.sink()
  • Pipe.SourceChannel    使用pipe.source()

 

三、Buffer缓冲

除了boolean类型没有Buffer类,其他七种基本数据类型都有Buffer缓冲。而byte有两个Buffer缓冲,一个是在堆,一个在文件的内存映射区.

方法clear()  清空Buffer

方法compact()移动Buffer数据到起始位置,设置为position在数据末尾

方法flip() 反转Buffer,将写模式转成读模式

方法rewind() 从0开始读数据

方法hasRemaining()判断是否还有剩余数据

ByteBuffer

ShortBuffer

IntBuffer

LongBuffer

FloatBuffer

DoubleBuffer

CharBuffer

MappedByteBuffer        通过FileChannel.map方法产生

 

四、Selector 选择器

Selector selector = Selector.open();
channel.configureBlocking(false);
SelectionKey key = channel.register(selector,Selectionkey.OP_READ);

select方法

int select()
int select(long timeout)
int selectNow()

select()阻塞到至少有一个通道在你注册的事件上就绪了。

select(long timeout)和select()一样,除了最长会阻塞timeout毫秒(参数)。

selectNow()不会阻塞,不管什么通道就绪都立刻返回

 

调用Selector.wakeup()方法,阻塞在select()方法上的线程会立马返回。

用完Selector后调用其close()方法会关闭该Selector,且使注册到该Selector上的所有SelectionKey实例无效。通道本身并不会关闭。

 

五、SelectionKey

Selector四种事件用SelectionKey的四个常量来表示:

SelectionKey.OP_CONNECT

SelectionKey.OP_ACCEPT

SelectionKey.OP_READ

SelectionKey.OP_WRITE

 

在Selector的select方法返回不为0时,获取SelectionKey

Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator keyIterator = selectedKeys.iterator();
while(keyIterator.hasNext()) {
SelectionKey key
= keyIterator.next(); if(key.isAcceptable()) { // a connection was accepted by a ServerSocketChannel. } else if (key.isConnectable()) { // a connection was established with a remote server. } else if (key.isReadable()) { // a channel is ready for reading } else if (key.isWritable()) { // a channel is ready for writing } keyIterator.remove(); //必须移除掉,否则下一次channel还留在selectionkeySet中。 }

 

六、Pipe 管道

 (1)SinkChannel

Pipe pipe = Pipe.open();
Pipe.SinkChannel sinkChannel = pipe.sink();
String data = "a sink pipe channel";
ByteBuffer buf = ByteBuffer.allocate(50);
buf.clear();
buf.put(data.getBytes());
buf.flip();

while(buf.hasRemaining()) {
    sinkChannel.write(buf);
}

 

(2)SourceChannel

Pipe.SourceChannel sourceChannel = pipe.source();
ByteBuffer buf = ByteBuffer.allocate(50);
int length = sourceChannel.read(buf);

 

 七、FileLock

FileLock与Lock接口相似,但没有实现Lock接口

(1)概念

  • 共享锁: 共享读操作,但只能一个写(读可以同时,但写不能)
  • 独占锁: 只有一个读或一个写(读和写都不能同时)

(2)FileLock FileChannel.lock(long position, long size, boolean shared)

shared的含义:是否使用共享锁,一些不支持共享锁的操作系统,将自动将共享锁改成排它锁。可以通过调用isShared()方法来检测获得的是什么类型的锁。

(3) lock()和tryLock()的区别:

lock()阻塞的方法,锁定范围可以随着文件的增大而增加。无参lock()默认为独占锁;有参lock(0L, Long.MAX_VALUE, true)为共享锁。

tryLock()非阻塞,当未获得锁时,返回null.

(4)FileLock的生命周期:在调用FileLock.release(),或者Channel.close(),或者JVM关闭

(5)FileLock是线程安全的

(6)同一进程内,在文件锁没有被释放之前,不可以再次获取。即在release()方法调用前,只能lock()或者tryLock()一次。

        FileChannel channel = null;
        FileLock lock=null;
        try {
            RandomAccessFile raf = new RandomAccessFile("data.txt", "rw");
            channel = raf.getChannel();
            //获得锁方法一:lock(),阻塞的方法,当文件锁不可用时,当前进程会被挂起  
            lock = channel.lock();//无参lock()为独占锁  
            //lock = channel.lock(0L, Long.MAX_VALUE, true);//有参lock()为共享锁,有写操作会报异常  

            //获得锁方法二:trylock(),非阻塞的方法,当文件锁不可用时,tryLock()会得到null值  
            //do {  
            //  lock = channel.tryLock();  
            //} while (null == lock); 
        } catch (Exception e) {
        }finally{
            if (lock!=null) {
                lock.release();
            }
            if (channel!=null) {
                channel.close();
            }
        }

 

 八、ServerSocketChannel 服务器通道

package cn.edu.scau.mk;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

/**
 *
 * @author MK
 */
public class Test {

    volatile static boolean isFinished = false;

    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(888));
        while (!isFinished) {
            SocketChannel socketChannel = serverSocketChannel.accept();
            //1.阻塞模式
            //线程处理socketChannel...
            //2.非阻塞模式
            if (socketChannel != null) {
                //处理socketChannel...
            }

        }
        serverSocketChannel.close();

    }
}

 

九、SocketChannel TCP通道

package cn.edu.scau.mk;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

/**
 *
 * @author MK
 */
public class Test {

    volatile static boolean isFinished = false;

    public static void main(String[] args) throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);//设置为非阻塞
        socketChannel.connect(new InetSocketAddress("https://www.baidu.com", 80));
        String data = "a socket channel connect";
        ByteBuffer buf = ByteBuffer.allocate(48);
        buf.clear();
        buf.put(data.getBytes());
        buf.flip();
        while (!socketChannel.finishConnect()) {
            //等待连接成功或者做其他的事
        }
        //非阻塞状态有可能没有写入数据就返回了
        while (buf.hasRemaining()) {
            socketChannel.write(buf);
        }
        socketChannel.close();
    }
}

 

十、DatagramChannel UDP通道

package cn.edu.scau.mk;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SocketChannel;

/**
 *
 * @author MK
 */
public class Test {

    volatile static boolean isFinished = false;

    public static void main(String[] args) throws IOException {
        DatagramChannel channel = DatagramChannel.open();
        channel.socket().bind(new InetSocketAddress(888));
        //channel.connect(new InetSocketAddress("www.baidu.com", 80));
        ByteBuffer buf = ByteBuffer.allocate(48);
        buf.clear();
        //接收
        SocketAddress sa=channel.receive(buf);
        //connect通道可以使用read
        //int bytesRead = channel.read(buf);

        buf.clear();
        buf.put("datagram channel".getBytes());
        buf.flip();
        //发送
        int length = channel.send(buf, new InetSocketAddress("www.baidu.com", 80));
        //connect通道可以使用write
        //channel.write(buf);
        channel.close();
    }
}

 



以上是关于Java NIO总结的主要内容,如果未能解决你的问题,请参考以下文章

Java NIO总结

java-----NIO总结

NIO学习总结

Java NIO 学习总结 学习手册

java----IO和NIO的区别

java-----NIO总结