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总结的主要内容,如果未能解决你的问题,请参考以下文章