Java NIO---Channel部分
Channel 是連接buffer和Io設備之間的管道,當然channel也可以一頭連接channel
Basic Channel Interface:
public interface Channel
{
public boolean isOpen( );
public void close( ) throws IOException;
}
1.open channel
channel作為i/o 設備的管道,分為兩種,一種文件(file),另一種是端口(Socket)
file相關的只有fileChannel
socket相關的有SocketChannel, ServerSocketChannel和DatagramChannel.
socket channel可以通過factory創建新的socket channel
比如
SocketChannel sc = SocketChannel.open( );
sc.connect (new InetSocketAddress ("somehost", someport));
ServerSocketChannel ssc = ServerSocketChannel.open( );
ssc.socket( ).bind (new InetSocketAddress (somelocalport));
而fileChannel 則不能這樣,他是在一個打開的andomAccessFile, FileInputStream或者FileOutputStream
對象上getChannel()
比如
RandomAccessFile raf = new RandomAccessFile ("somefile", "r");
FileChannel fc = raf.getChannel( );
2.Using Channels
三個接口:
public interface ReadableByteChannel
extends Channel
{
public int read (ByteBuffer dst) throws IOException;
}
public interface WritableByteChannel
extends Channel
{
public int write (ByteBuffer src) throws IOException;
}
public interface ByteChannel
extends ReadableByteChannel, WritableByteChannel
{
}
需要注意的是 fileChannel 雖然也有write,read方法,但是他們能否調用write read方法是由file相關的訪問權限決定的。
channel 有blocking和nonblocking兩種模式,nonblocking是指永遠不會將一個正在調用的線程sleep,他們被請求的結果要么
立刻完成,要么返回一個nothing的結果。
只有stream-oriented的channels(比如sockets and pipes)可以用nonblocking模式
3.Closing Channels
和buffer不一樣,channel不能被重用,用完之后一定要close,此外當一個線程被設置為interrupt狀態,當該線程試圖訪問某個channel
的話,該channel將立刻關閉。
4.Scatter/Gather
當我們在多個buffer上執行一個i/O操作的時候,我們需要將多個buffer放在一個buffer數組一并讓channel來處理
Scatter/Gather interface:
public interface ScatteringByteChannel
extends ReadableByteChannel
{
public long read (ByteBuffer [] dsts)
throws IOException;
public long read (ByteBuffer [] dsts, int offset, int length)
throws IOException;
}
public interface GatheringByteChannel
extends WritableByteChannel
{
public long write(ByteBuffer[] srcs)
throws IOException;
public long write(ByteBuffer[] srcs, int offset, int length)
throws IOException;
}
例子:
ByteBuffer header = ByteBuffer.allocateDirect (10);
ByteBuffer body = ByteBuffer.allocateDirect (80);
ByteBuffer [] buffers = { header, body };
int bytesRead = channel.read (buffers);
5.File Channels
filechannel 只能是blocking模式也就是被鎖住模式,不能是nonblocking模式
public abstract class FileChannel
extends AbstractChannel
implements ByteChannel, GatheringByteChannel, ScatteringByteChannel
{
// This is a partial API listing
public abstract void truncate (long size)
public abstract void force (boolean metaData)
}
fileChannel 中有truncate和force 兩個方法
truncate (long size)是以給定的size來切斷file
force (boolean metaData) file屬性的修改立刻影響到disk上
6.File Locking
file 鎖雖然在fileChannel中提出,但是需要注意本身lock是和file相關,而且不同的操作系統提供的file也有不同,和channel無關的
public abstract class FileChannel
extends AbstractChannel
implements ByteChannel, GatheringByteChannel, ScatteringByteChannel
{
// This is a partial API listing
public final FileLock lock( )
public abstract FileLock lock (long position, long size,
boolean shared)
public final FileLock tryLock( )
public abstract FileLock tryLock (long position, long size,
boolean shared)
}
lock 有三個參數,第一個是開始鎖住的file的postion, 第二個是鎖住的file大小,前面這兩個參數就能定義了一塊lock范圍,第三個是
顯示lock是shared(true)類型還是exclusive(false)類型,
沒有參數的lock()其實等同于fileChannel.lock (0L, Long.MAX_VALUE, false);
FileLock 本身是線程安全的,可以多個線程同時訪問
tryLock() 和Lock()相似,當某個lock因為其他原因不能被獲取,那么就要用tryLock() 這個時候就返回null
FileLock總關聯一個特定的channel,可以通過channel()獲取相關聯的channel,當FileLock release(),那么對于的channel也就相應的close();
7.Memory-Mapped Files
Memory-mapped files 一般效率更高,而且因為他是和操作系統相關的,所有他不會消費jvm分配的內存
通過map()來建立MappedByteBuffer,
mapped buffers和lock有點不同,lock和產生它的channel綁定,如果channel closed那么lock也就消失
而mapped buffers本身也沒有ummap方法,他是通過自身不再被引用然后被系統垃圾回收的。
8.Channel-to-Channel Transfers
channel直接的傳輸可以提供更好的效率
public abstract class FileChannel
extends AbstractChannel
implements ByteChannel, GatheringByteChannel, ScatteringByteChannel
{
// This is a partial API listing
public abstract long transferTo (long position, long count,
WritableByteChannel target)
Java NIO
90
public abstract long transferFrom (ReadableByteChannel src,
long position, long count)
}
這個是能在filechannel之間使用,兩個socketchannel之間不能直接使用transferTo和transferFrom,但是因為socketchannel繼承WritableByteChannel and ReadableByteChannel,所有可以將一個文件的內容transferTo socketChannel或直接通過transferFrom從socketChannel中讀取數據
9.Socket Channels
對應以前一般一個線程對應一個socket,而在NIO中可以一個線程對應成百上千的socket,同時沒有性能降低的問題
三種socket channel(DatagramChannel,SocketChannel, and ServerSocketChannel)
DatagramChannel和SocketChannel 有read和write的方法
而ServerSocketChannel 則是監聽connection和創建SocketChannel,他本身不參與數據的傳輸
這三個channel都可以通過socket()方法獲取到對應的Socket,ServerSocket,DatagramSocket
需要說明的是,socket不一樣要綁定channel,通過傳統的new 創建socket,那么getChannel()就會返回null
SocketChannel 有Nonblocking和blocking 兩種模式
SocketChannel sc = SocketChannel.open( );
sc.configureBlocking (false); // nonblocking
...
if ( ! sc.isBlocking( )) {
doSomething (cs);
}
可以通過configureBlocking 來設置,true表示blocking mode 而false 表示nonblocking mode
對應大型應用并發處理的 建議使用nonblocking mode
看看下面的例子:
Socket socket = null;
Object lockObj = serverChannel.blockingLock( );
// have a handle to the lock object, but haven't locked it yet
// may block here until lock is acquired
synchronize (lockObj)
{
// This thread now owns the lock; mode can't be changed
boolean prevState = serverChannel.isBlocking( );
serverChannel.configureBlocking (false);
socket = serverChannel.accept( );
serverChannel.configureBlocking (prevState);
}
// lock is now released, mode is allowed to change
if (socket != null) {
doSomethingWithTheSocket (socket);
}
體驗一下 blockingLock()和lock()的區別
SocketChannel 可以通過finishConnect( ),isConnectPending( ), or isConnected( )獲取當前connection的狀態
socket是面向流的,datagram是面向packet的
因此DatagramChannel 就是面向packet協議的channel,比如UDP/IP
10.pipe 方式 可以研究一下