1柬唯、什么是Java NIO?
同步非阻塞io模式认臊,拿燒開水來說,NIO的做法是叫一個線程不斷的輪詢每個水壺的狀態(tài)锄奢,看看是否有水壺的狀態(tài)發(fā)生了改變失晴,從而進行下一步的操作。
Java NIO有三大組成部分:Buffer拘央;Channel涂屁;Selector。
通過事件驅(qū)動模式實現(xiàn)了什么時候有數(shù)據(jù)可讀的問題灰伟。? Channel:相當于IO操作的載體拆又,相當于一個硬件設(shè)備儒旬,一個文件,一個socket或是區(qū)別程序中的不同IO操作帖族,如read栈源,write。
channel類似流竖般,但又有些不同:? 既可以從通道中讀取數(shù)據(jù)甚垦,又可以寫數(shù)據(jù)到通道。但流的讀寫通常是單向的涣雕。? 通道可以異步地讀寫艰亮。? 通道中的數(shù)據(jù)總是要先讀到一個Buffer,或者總是要從一個Buffer中寫入挣郭。
Buffer:用于和NIO通道進行交互迄埃。如你所知,數(shù)據(jù)是從通道讀入緩沖區(qū)丈屹,從緩沖區(qū)寫入到通道中的调俘。? 緩沖區(qū)本質(zhì)上是一塊可以寫入數(shù)據(jù),然后可以從中讀取數(shù)據(jù)的內(nèi)存旺垒。這塊內(nèi)存被包裝成NIO Buffer對象彩库,并提供了一組方法,用來方便的訪問該塊內(nèi)存先蒋。? channel 和 buffer 之間的交互如下:
Selector:Selector(選擇器)是Java NIO中能夠檢測一到多個NIO通道骇钦,通道將關(guān)心的事件注冊到selector 上,selector能夠知曉通道是否為這些事件諸如讀寫事件做好數(shù)據(jù)準備竞漾。這樣眯搭,一個單獨的線程可以管理多個channel,從而管理多個網(wǎng)絡(luò)連接业岁。
2鳞仙、什么是Java BIO?
同步阻塞IO模式,數(shù)據(jù)的讀取寫入必須阻塞在一個線程內(nèi)等待其完成笔时。這里使用那個經(jīng)典的燒開水例子棍好,這里假設(shè)一個燒開水的場景,有一排水壺在燒開水允耿,BIO的工作模式就是借笙, 叫一個線程停留在一個水壺那,直到這個水壺燒開较锡,才去處理下一個水壺业稼。但是實際上線程在等待水壺燒開的時間段什么都沒有做。不知道io操作中什么時候有數(shù)據(jù)可讀蚂蕴,所以一直是阻塞的模式低散。
3俯邓、區(qū)別及應(yīng)用
主要區(qū)別:
兩種模式的差異對比:
首先,線程是較為重量級的資源谦纱。bio當并發(fā)量大看成,而后端服務(wù)或客戶端處理數(shù)據(jù)慢時就會產(chǎn)生產(chǎn)生大量線程處于等待中,即上述的阻塞跨嘉,是非常嚴重的資源浪費川慌。
此外,線程的切換也會導(dǎo)致cpu資源的浪費祠乃,單機內(nèi)存限制也無法過多的線程梦重,只能單向以流的形式讀取數(shù)據(jù)。
nio使用單線程或者只使用少量的多線程亮瓷,多個連接共用一個線程琴拧,消耗的線程資源會大幅減小。并且當處于等待(沒有事件)的時候線程資源可以釋放出來處理別的請求嘱支,通過事件驅(qū)動模型當有accept/read/write等事件發(fā)生后通知(喚醒)主線程分配資源來處理相關(guān)事件蚓胸。以buffer緩沖區(qū)的形式處理數(shù)據(jù),處理更為方便除师。
nio server demo:
Selector selector = Selector.open();?
ServerSocketChannel ssc = ServerSocketChannel.open();?
ssc.configureBlocking(false);?
ssc.socket().bind(new InetSocketAddress(port));?
ssc.register(selector, SelectionKey.OP_ACCEPT);?
while (true) {?
? ? // select()阻塞沛膳,等待有事件發(fā)生喚醒?
? ? int selected = selector.select();?
? ? if (selected > 0) {?
? ? ? ? Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();?
? ? ? ? while (selectedKeys.hasNext()) {?
? ? ? ? ? ? SelectionKey key = selectedKeys.next();?
? ? ? ? ? ? if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {?
? ? ? ? ? ? ? SocketChannel client = ((ServerSocketChannel) key.channel()).accept();
? ? ? ? ? ? ? ? // 處理 accept 事件?
? ? ? ? ? ? ? ? //注冊read事件
? ? ? ? ? ? ? ? client.configureBlocking(false);
? ? ? ? ? ? ? ? client.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufSize));
? ? ? ? ? ? } else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {?
? ? ? ? ? ? ? ? // 處理 read 事件?
? ? ? ? ? ? ? //注冊write事件
? ? ? ? ? ? } else if ((key.readyOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {?
? ? ? ? ? ? ? ? // 處理 write 事件?
? ? ? ? ? ? }?
? ? ? ? ? ? selectedKeys.remove();?
? ? ? ? }?
? ? }?
}
bio server demo:
ServerSocket serverSocket;
? ? ? ? try {
? ? ? ? ? ? serverSocket = new ServerSocket(8000);
? ? ? ? ? ? while (true){
? ? ? ? ? ? ? ? Socket socket = serverSocket.accept();
? ? ? ? ? ? ? ? new Thread(()->{
? ? ? ? ? ? ? ? ? ? try (InputStream inputStream = socket.getInputStream(); OutputStream outputStream =? socket.getOutputStream()) {
? ? ? ? ? ? ? ? ? ? ? ? byte[] bytes =new byte[1024];
? ? ? ? ? ? ? ? ? ? ? ? while (inputStream.read(bytes) != -1){
? ? ? ? ? ? ? ? ? ? ? ? ? ? outputStream.write(bytes);
? ? ? ? ? ? ? ? ? ? ? ? ? ? bytes = new byte[1024];
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }catch (IOException e){
? ? ? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }).start();
? ? ? ? ? ? }
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
4、Java學習視頻
Java基礎(chǔ):
Java300集汛聚,Java必備優(yōu)質(zhì)視頻_手把手圖解學習Java锹安,讓學習成為一種享受
Java項目:
【Java游戲項目】1小時教你用Java語言做經(jīng)典掃雷游戲_手把手教你開發(fā)游戲
【Java畢業(yè)設(shè)計】OA辦公系統(tǒng)項目實戰(zhàn)_OA員工管理系統(tǒng)項目_java開發(fā)