Netty一:Java bio nio
Java支持的I/O模型
Java共支持3種網絡編程模型/IO模式:BIO、NIO、AIO
JavaBIO:同步并阻塞(傳統阻塞型),服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷
JavaNIO:同步非阻塞,服務器實現模式為一個線程處理多個請求(連接),即客戶端發送的連接請求都會注冊到多路復用器上,多路復用器輪詢到連接有I/O請求就進行處理
JavaAIO:異步非阻塞,AIO引入異步通道的概念,采用了Proactor模式,簡化了程序編寫,有效的請求才啟動線程,它的特點是先由操作系統完成后才通知服務端程序啟動線程去處理,一般適用于連接數較多且連接時間較長的應用
BIO
BIO(blocking I/O):同步阻塞,服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,可以通過線程池機制改善(實現多個客戶連接服務器)
NIO
Java NIO的非阻塞模式,使一個線程從某通道發送請求或者讀取數據,但是它僅能得到目前可用的數據,如果目前沒有數據可用時,就什么都不會獲取,而不是保持線程阻塞,所以直至數據變的可以讀取之前,該線程可以繼續做其他的事情。 非阻塞寫也是如此,一個線程請求寫入一些數據到某通道,但不需要等待它完全寫入,這個線程同時可以去做別的事情,NIO的三大核心組件Buffer,Channel,Selector
NIO和BIO的區別
1.BIO 以流的方式處理數據,而 NIO 以塊的方式處理數據,塊 I/O 的效率比流 I/O 高很多
2.BIO 是阻塞的,NIO 則是非阻塞的
3.BIO基于字節流和字符流進行操作,而 NIO 基于 Channel(通道)和 Buffer(緩沖區)進行操作,數據總是從通道讀取到緩沖區中,或者從緩沖區寫入到通道中。Selector(選擇器)用于監聽多個通道的事件(比如:連接請求,數據到達等),因此使用單個線程就可以監聽多個客戶端通道
Buffer
緩沖區本質上是一個可以讀寫數據的內存塊,可以理解成是一個容器對象(含數組),該對象提供了一組方法,可以更輕松地使用內存塊,,緩沖區對象內置了一些機制,能夠跟蹤和記錄緩沖區的狀態變化情況。Channel提供從文件、網絡讀取數據的渠道,但是讀取或寫入的數據都必須經由 Buffer
Buffer類相關
Buffer 重要屬性
Capacity:容量,即可以容納的最大數據量;在緩沖區創建時被設定并且不能改變
Limit:表示緩沖區的當前終點,不能對緩沖區超過極限的位置進行讀寫操作。且極限是可以修改的
Position:位置,下一個要被讀或寫的元素的索引,每次讀寫緩沖區數據時都會改變改值,為下次讀寫作準備
Mark:標記
Buffer 實例代碼
import java.nio.Buffer;
import java.nio.IntBuffer;
public class NIOBuffer {
public static void main(String[] args){
//創建一個Buffer
IntBuffer intBuffer = IntBuffer.allocate(5);
printBuffer(intBuffer);
intBuffer.put(1);
intBuffer.put(2);
intBuffer.put(3);
intBuffer.put(4);
intBuffer.put(5);
printBuffer(intBuffer);
intBuffer.flip();
printBuffer(intBuffer);
while (intBuffer.hasRemaining()){ //表示當前位置和限制元素之間還有元素
System.out.println(intBuffer.get());
}
printBuffer(intBuffer);
}
public static void printBuffer(Buffer buffer){
System.out.println("position:"+buffer.position());
System.out.println("limit:"+buffer.limit());
System.out.println("capacity:"+buffer.capacity());
System.out.println("mark:"+buffer.mark());
System.out.println("..................... ");
}
}
Channel
NIO的通道類似于流,但是相比于流,通道可以同時進行讀寫數據,而流只能讀或者只能寫,通道能夠異步讀寫數據,通道可以在緩沖區中讀數據,也可以寫數據到緩沖區
Channel類相關
常用的 Channel 類有:FileChannel、DatagramChannel、ServerSocketChannel 和 SocketChannel。【ServerSocketChanne 類似 ServerSocket , SocketChannel 類似 Socket】。
FileChannel 用于文件的數據讀寫,DatagramChannel 用于 UDP 的數據讀寫,ServerSocketChannel 和 SocketChannel 用于 TCP 的數據讀寫
Channel實例代碼1
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NIOFileChannel1 {
public static void main(String[] args) throws IOException {
String str = "hello channel";
FileOutputStream fileOutputStream = new FileOutputStream("E:\\Workspace\\javaiopractice\\src\\main\\resources\\data");
//通過流獲取channel
FileChannel fileChannel = fileOutputStream.getChannel();
//創建一個緩沖區 ByteBuffer
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//將str存儲到byteBuffer
byteBuffer.put(str.getBytes());
//對byteBuffer 進行flip
byteBuffer.flip();
//將byteBuffer數據寫入到fileChannel
fileChannel.write(byteBuffer);
fileOutputStream.close();
}
}
Channel實例代碼2
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NIOFileChannel2 {
public static void main(String[] args) throws IOException {
//創建文件的輸入流
File file = new File("E:\\Workspace\\javaiopractice\\src\\main\\resources\\data");
FileInputStream fileInputStream = new FileInputStream(file);
//通過fileInputStream 獲取對應的FileChannel
FileChannel fileChannel = fileInputStream.getChannel();
//創建緩沖區
ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length());
//將通道的數據讀入buffer
fileChannel.read(byteBuffer);
//將byteBuffer的數據由字節轉成string
System.out.println(new String(byteBuffer.array()));
fileInputStream.close();
}
}
Channel實例3
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NIOFileChannel3 {
/**
* 使用一個Buffer完成文件讀取
*/
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("1.txt");
FileChannel fileChannel1 = fileInputStream.getChannel();
FileOutputStream fileOutputStream = new FileOutputStream("2.txt");
FileChannel fileChannel2 = fileOutputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(5);
while (true){
byteBuffer.clear(); //清空Buffer
int read = fileChannel1.read(byteBuffer); //從channel中讀取數據到buffer
System.out.println("read="+read);
if(read==-1){ //讀取完成
break;
}
byteBuffer.flip();
fileChannel2.write(byteBuffer);
}
//關閉相關的流
fileInputStream.close();
fileOutputStream.close();
}
}
Channel實例4
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
/**
* 使用transferFrom轉換通道寫數據
*/
public class NIOFileChannel4 {
public static void main(String[] args) throws IOException {
//創建相關流
FileInputStream fileInputStream = new FileInputStream("source.txt");
FileOutputStream fileOutputStream = new FileOutputStream("target.txt");
//獲取fileChannel
FileChannel sourceChannel = fileInputStream.getChannel();
FileChannel targetChannel = fileOutputStream.getChannel();
//使用transferForm完成拷貝
targetChannel.transferFrom(sourceChannel,0,sourceChannel.size());
sourceChannel.close();
targetChannel.close();
fileInputStream.close();
fileOutputStream.close();
}
}
Selector
Java的NIO是非阻塞的IO方式,采用Selector,可以使用一個線程來處理讀個客戶端連接,Selector 能夠檢測多個注冊的通道上是否有事件發生(注意:多個Channel以事件的方式可以注冊到同一個Selector),如果有事件發生,便獲取事件然后針對每個事件進行相應的處理。這樣就可以只用一個單線程去管理多個通道,也就是管理多個連接和請求。
Selector相比于BIO的優勢
1.只有在 連接/通道 真正有讀寫事件發生時,才會進行讀寫,就大大地減少了系統開銷,并且不必為每個連接都創建一個線程,不用去維護多個線程
2.避免了多線程之間的上下文切換導致的開銷
Selector相關類
ServerSocketChannel類
ServerSocketChannel在服務器端監聽新的客戶端Socket連接
SocketChannel類
網絡IO通道,具體負責進行讀寫操作。NIO把緩沖區的數據寫入通道,或者把通道里的數據讀到緩沖區
AIO
1.JDK 7 引入了 Asynchronous I/O,即 AIO。在進行 I/O 編程中,常用到兩種模式:Reactor和 Proactor。Java 的 NIO 就是 Reactor,當有事件觸發時,服務器端得到通知,進行相應的處理
2.AIO 即 NIO2.0,叫做異步不阻塞的 IO。AIO 引入異步通道的概念,采用了 Proactor 模式,簡化了程序編寫,有效的請求才啟動線程,它的特點是先由操作系統完成后才通知服務端程序啟動線程去處理,一般適用于連接數較多且連接時間較長的應用
智能推薦
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...
styled-components —— React 中的 CSS 最佳實踐
https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...
猜你喜歡
19.vue中封裝echarts組件
19.vue中封裝echarts組件 1.效果圖 2.echarts組件 3.使用組件 按照組件格式整理好數據格式 傳入組件 home.vue 4.接口返回數據格式...
【一只蒟蒻的刷題歷程】【藍橋杯】歷屆試題 九宮重排 (八數碼問題:BFS+集合set)
資源限制 時間限制:1.0s 內存限制:256.0MB 問題描述 如下面第一個圖的九宮格中,放著 1~8 的數字卡片,還有一個格子空著。與空格子相鄰的格子中的卡片可以移動到空格中。經過若干次移動,可以形成第二個圖所示的局面。 我們把第一個圖的局面記為:12345678. 把第二個圖的局面記為:123.46758 顯然是按從上到下,從左到右的順序記錄數字,空格記為句點。 本題目的任務是已知九宮的初態...
dataV組件容器寬高發生變化后,組件不會自適應解決方法
項目中需要大屏幕數據展示,于是使用了dataV組件,但是使用是發現拖動瀏覽器邊框,dataV組件顯示異常,如圖: 于是查了官網,官網的解釋如下: 于是按照官網的意思編寫代碼: 于是可以自適應了...
CSS3干貨10:如何做一個板塊標題水平線左邊帶顏色效果
很多網站在設計欄目標題的時候,喜歡用下劃線分開欄目標題和內容部分。 而且線條左邊的部分往往還有顏色,且這個顏色跟標題的文字長短保持一致。效果如圖所示: 這種效果其實很簡單。 我這里給大家推薦兩種方式: 假定我們的標題部分 HTML 結構如下: 方式一:利用下邊框。灰色部分是 h1 的下邊框,藍色部分是 span 標簽的下邊框。 h1 的高度為 40px,span 也設置它的高度為 40px。這樣,...