標籤:成功 int writing 反轉 java nio select net timeout nal
一、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類,其他七種基礎資料型別 (Elementary Data Type)都有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總結