• 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();
        }
    }
  • 相关阅读:
    暑假周总结02
    音乐播放器
    setInterval、控制停止和继续
    暑假周总结01
    ul li、a标签的下划线
    innerHTML、document获取对象、className修改样式
    领扣(LeetCode)N叉树的层序遍历 个人题解
    领扣(LeetCode)两句话中的不常见单词 个人题解
    领扣(LeetCode)二叉树的中序遍历 个人题解
    领扣(LeetCode)用队列实现栈 个人题解
  • 原文地址:https://www.cnblogs.com/maokun/p/7534873.html
Copyright © 2020-2023  润新知