java NIO概述
一 . 什么是線層阻塞?
線程阻塞即線程高風亮節讓出或放棄CPU,暫停執行,只有等到導致阻塞的原因解除,才能恢復運行;或者被其他線程中斷,該線程會退出阻塞狀態,并且拋出InterrutedException.
?
?
二 .常見的導致線程阻塞的原因:
????? ?線程執行了Thread.sleep(intn)方法,線程放棄CPU,睡眠n毫秒,然后恢復運行。但是此時被該線程所控制的同步代碼塊的鎖定釋放權利依然屬于該線程,其他線程依然不能訪問該代碼塊。
????? ?線程要執行一段同步代碼,由于無法獲得相關的同步鎖,只好進入阻塞狀態,等到獲得了同步鎖才能恢復運行。
????? ?線程執行了一個對象的wait()方法,進入阻塞狀態,只有等到其他線程執行了該對象的notify()或notifyAll()方法,才可將其喚醒。
????? ?線程執行I/O操作或進行遠程通信時,會因為等待相關的資源而進入阻塞狀態。例如,當線程執行System.in.read()方法時,如果用戶沒有向控制臺輸入數據,則該線程會一直等到了用戶的輸入數據才才read()方法返回。
?
?
三 .什么是非阻塞
????? 所謂非阻塞,就是指當線程執行某些方法時,如果操作還沒有就緒,就立即返回,而不會一直等到操作就緒。
?
四 .什么是阻塞I/O和非阻塞I/O
????? 可能出現阻塞的輸入和輸出操作被稱為阻塞I/O;于此對照,如果執行輸入和輸出操作時,不會發生阻塞,則稱為非阻塞I/O。
?
五 .Java.nio包提供了支持非阻塞通信的類
· ServerSocketChannel:ServerSocket的替代類,支持阻塞通信和非阻塞通信。
· SocketChannel: Socket的替代類,支持阻塞通信和非阻塞通信。
· Selector: 為ServerSocketChannel監控連接就緒事件,為SocketChannel監控連接就緒,讀就緒和寫就緒事件。
· SelectionKey: 代表ServerSocketChannel及SocketChannel注冊事件的句柄。當一個SelectionKey對象位于Selector對象的selector-keys集合中時,就表示與這個SeletionKey對象相關的事件發生了。
· Charset類:代表字符編碼,它提供了把字節流轉換為字符串(解碼過程)
和把字符串轉換為字節流(編碼過程)的使用方法。
?
· Buffer: 數據輸入和輸出往往是比較耗時的操作。緩沖區從兩個方面提高I/O操作的效率:
?????????? §減少實際的物理讀寫次數;
?????????? §緩沖區在創建時被分配內存,這塊內存區域一直被重用,這可以減少動態分配和回收內存區域的次數,可以通過修改緩沖區的極限屬性來達到緩沖區重用的目的;
·緩沖區提供了三個屬性來控制緩沖區的使用:容量,極限和位置,詳細介紹參考java API文檔;于此同時緩沖區還提供了用于改變以上3個屬性的方法
?????????? ? clear(): 把極限設置為容量的值,再把位置設為0
?????????? ? flip(): 把極限設置為位置的值,再把位置設為0
?????????? ? rewind():不改變極限的值,把位置設為0
其中,flip()方法為從Buffer中取數據做好了準備,而clear()則向Buffer中裝入數據做好準備。
有關緩沖區的更加詳細的介紹請參考java API文檔。
·通道Channel用來連接緩沖區與數據源或數據匯(數據目的地)
通道創建時被打開,一旦關閉通道,就不能重新打開了
?????
??? ????
| 數據源 |
| 通道 |
| 緩沖區 |
| 通道 |
| 數據匯 |
?
?
????? ??
??????????
?
·高級通道操作:提供了分散讀取和集中寫數據的類和相關方法,可以進一步的提高輸入和輸出操作的速度,詳述請參考java API文檔。
?
?
§具有自動增長的緩沖區的ChannelIO類
????? ChannelIO對SocketChannel進行了包裝,增加了自動增長緩沖區容量的功能。當調用socketChannel.read(ByteBuffer buffer)方法時,如果buffer已滿(position=limit)那么即使通道中還有未接收的數據,read方法也不會讀取任何數據,二是直接返回0,表示讀到了0個字節。
????? 為了能讀取通道中的所有數據,必須保證緩沖區的容量足夠大。在ChannelIO類中,有一個requestBuffer變量,它用來存放客戶的HTTP請求數據,當requestBuffer剩余容量已經不足5%,并且還有HTTP請求數據未接收時,ChannelIO會自動擴充requestBuffer的容量,該功能由resizeRequestBuffer()方法完成。
????? 如下所示是ChannelIO類的源程序,它的read()和write()方法利用SocketChannel來接收和發送數據,并且它還提供了實用方法transferTo(),該方法能把文件中的數據發送到SockChannel中
?
?
?
?
????? //此處省略import語句
????? Public class ChannelIO{
?????????? Protected SocketChannelsocketChannel;
?????????? //存放請求數據
?????????? Protected ByteBuffer requestBuffer;
?????????? Private static int requestBufferSize= 4096;
?
?????????? Public ChannelIO() throwsIOException{
???????????????? this.socketChannel =socketChannel;
???????????????? //設置模式為阻塞模式或非阻塞模式
???????????????? socketChannel.configureBlocking(blocking);
???????????????? requestBuffer =ByteBuffer.allocate(requestBufferSize);
}
?
Public SocketChannel getSocketChannel(){
????? ReturnsocketChannel;
}
?
/**
*
*如果原緩沖區的剩余容量不夠,就創建一個新的緩沖區,容量為原來的兩倍,把原來緩沖區的數據復制到新緩沖區
*
/
Protected void resizeRequestBuffer(intremaining){
????? If(requestBuffer.remaining()< remianing){
?????????? //把容量增大到原來的兩倍
?????????? ByteBufferbb = ByteBuffer.allocate(requestBuffer.capcity()*2);
?????????? //把極限設置為位置的值
?????????? requestBuffer.flip();
?????????? //把原來緩沖區中的數據復制到新的緩沖區
?????????? bb.put(requestBuffer);
?????????? requestBuffer= bb;
}
}
?
//接受數據,把它們存放到requestBuffer中,如果requestBuffer的剩余容量不足5%,就通過resizeRequestBuffer(int remaining)方法擴充容量
Public int read() throws IOException {
????? resizeRequestBuffer(requestBufferSize/20);
????? returnsocketChannel.read(requestBuffer);
}
?
?
//返回requestBuffer,它存放了請求數據
Public ByteBuffer getReadBuf(){
????? ReturnrequestBuffer;
}
?
//發送參數指定的ByteBuffer中的數據
Public int write(ByteBuffer src) throwsIOException {
????? ReturnsocketChannel.write(src);
}
?
//把FileChannel中的數據寫到SocketChannel中
Public long transgerTo(FileChannel fc, longpos, long len) throws IOExcetion{
????? Returnfc.transferTo(pos,len,socketChannel);
}
?
//關閉SocketChannel
Public void close() throws IOException{
????? socketChannel.close();
}
}
?
?
總結
以上是生活随笔為你收集整理的java NIO概述的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python 统计文本中单词的个数
- 下一篇: PowerDesigner小技巧