java nio aio bio概念
title: java nio aio bio概念
date: 2018/1/13 21:12:55
tags: [nio,aio]
categories:
- 開發
- java
就目前來說,大多數的系統瓶頸在io , io的瓶頸又在定址 ……
跑題了,我先來記錄總結幾個基本概念吧
IO分兩階段:
1.資料準備階段
2.核心空間複製回用戶程序緩衝區階段
一般來講:阻塞IO模型、非阻塞IO模型、IO複用模型(select/poll/epoll)、訊號驅動IO模型都屬於同步IO,因為階段2是阻塞的(儘管時間很短)。只有非同步IO模型是符合POSIX非同步IO操作含義的,不管在階段1還是階段2都可以幹別的事。
阻塞和非阻塞
是程序訪問資料的時候,資料是否準備就緒的一種處理方式 。
當資料沒有準備好的時候:
-
阻塞
需要等待資料緩衝區中的資料準備好後,才處理其它事情
-
非阻塞
資料如果沒有準備好,直接返回
同步和非同步
基於應用程式
和作業系統
處理io事件所採用的方式
-
同步
-
應用程式直接參與io讀寫的操作
-
會阻塞在某個方法上等待io事件的完成(阻塞io事件 或者 通過輪詢方式)
-
阻塞io事件
不能做自己的事情,一直阻塞執行緒
-
IO事件輪詢方式(多路複用,Select模式)
讀寫事件交給一個單獨的(select)執行緒來處理,並完成io事件的註冊功能 ,然後不斷的輪詢讀寫緩衝區看資料是否準備好,有資料通知我們的讀寫執行緒 。這樣以前的讀寫執行緒可以做其它事情 ,因為這個時候阻塞的不是所有的io執行緒,而是select執行緒 (select 相當於一個管家)
但是它還是同步的,因為真正的io操作不是完全交給作業系統的,應用程式要參與
-
例子(把select比做管家,還有客人和主人):
當【客人】來拜訪【主人】的時候,先找到【管家】,【管家】得到這個註冊資訊後,跟【主人】說:我這裡來了一個或者多個【客人】,他們需要【主人】給他們某某東西 。這個時候【客人】可以去做其它事情,比如看看花園 。當【管家】得知【主人】準備好東西后,他就去找對應的某人 告訴這位【客人】主人給他某樣東西 ,這個時候阻塞是發生在 【管家】不是【客人】
-
-
-
非同步
-
所有的io操作交給OS處理
-
可以去做其它事情,並不需要去完成真正的io操作,當作業系統完成io後,給我們應用程式一個通知就行
-
-
例子(來源於網路)阻塞和非阻塞,同步和非同步
故事:老王燒開水。
出場人物:老張,水壺兩把(普通水壺,簡稱水壺;會響的水壺,簡稱響水壺)。
老王想了想,有好幾種等待方式
- 老王用水壺煮水,並且站在那裡,不管水開沒開,每隔一定時間看看水開了沒。-同步阻塞
老王想了想,這種方法不夠聰明。
- 老王還是用水壺煮水,不再傻傻的站在那裡看水開,跑去寢室上網,但是還是會每隔一段時間過來看看水開了沒有,水沒有開就走人。-同步非阻塞
老王想了想,現在的方法聰明瞭些,但是還是不夠好。
- 老王這次使用高大上的響水壺來煮水,站在那裡,但是不會再每隔一段時間去看水開,而是等水開了,水壺會自動的通知他。-非同步阻塞
老王想了想,不會呀,既然水壺可以通知我,那我為什麼還要傻傻的站在那裡等呢,嗯,得換個方法。
- 老王還是使用響水壺煮水,跑到客廳上網去,等著響水壺自己把水煮熟了以後通知他。-非同步非阻塞
老王豁然,這下感覺輕鬆了很多。
JAVA IO模型
BIO
graph TD Thread((Thread1)) --read-->InputStream1; InputStream1 --io-->Socket1; Thread2((Thread2)) --read-->InputStream2; InputStream2 --io-->Socket2; Thread3((Thread3)) --read-->InputStream3; InputStream3 --io-->Socket3;JDK1.4以前都是使用的bio
- 阻塞在讀寫方法
- 用阻塞到執行緒來改進效能,但是執行緒也是一個大的開銷
- 阻塞點
- server.accept()
- inputstream.read()
- 缺點
- 單執行緒情況下只能有一個客戶端訪問
- 用執行緒池可以有多個客戶端連線,但是非常消耗效能
NIO
graph LR; Thread((Thread))--select-->Selector; SocketChannel1--register-selectionkey-->Selector; SocketChannel2--register-selectionkey-->Selector; SocketChannel3--register-selectionkey-->Selector; SocketChannel1--io-->Socket1; SocketChannel2--io-->Socket2; SocketChannel3--io-->Socket3;New IO,Single thread blocked on selection
阻塞點
- selector.select();//當註冊的事件到達時 該方法返回 ,否則一直阻塞
- select()也可以不阻塞 ,select(millisecond) wakeup() selectNow()
- 單執行緒可以服務多個客戶端
Select模式
- 學習了linux的多路複用技術
- "多路複用" --這裡“多路”指的是多個網路連線,“複用”指的是複用同一個執行緒。採用多路 I/O 複用技術可以讓單個執行緒高效的處理多個連線請求(儘量減少網路 IO 的時間消耗)
- 如果你看select()方法的實現 你會發現:它是用c寫的
- windows通過winsocket實現
- linux通過select/poll/epoll實現
- 同步非阻塞 nio v1
- 實現IO事件的輪詢方式
- 常用的網路通訊框架 mina,netty
原理
selector要管理的事情:(所有的io事件)
- 客戶端的連線
- 服務端的accept
- 客戶端和服務端的讀寫
選擇器:當io事件註冊給我們的selector時,selector會分配一個key標記它,當io事件完成時通過這個標記來找到相應的管道,然後通過管道來發送和接收資料等操作
資料緩衝區:bytebuffer 提供很多讀寫方法
重要API:
// Selector
Selector select = Selector.open();
// Server point
ServerSocketChannel
// client point
SocketChannel
// 獲取io事件keys
Selectionkey keys = Selector.selectedKeys();
// 註冊到selector
channel.register(Selector,SelectedKeys.OP_WRITE)
例子
-
客人到餐廳點菜
-
餐廳(系統) ; 餐廳大門(ServerSocketChannel); 客人(客戶端-SocketChannel); 服務員(selector + 執行緒);
AIO
-
jdk1.7以後 nio v2
-
學習了linux epoll 模式
-
原理
-
AsynchronousServerSocketChannel
-
AsynchronousSocketChannel
-
使用者處理器:interface CompletionHandler
- 這個介面向作業系統發起IO請求,當完成後處理具體邏輯,否則做自己該做的事情
- completed(V result, A attachment)方法
- fail(Throwable exc result, A attachment)方法
-
小結
- NIO AIO 原理就是在原來的(serversocket,socket)基礎上做了改進
- 對讀寫管道進行了抽象,管道Channel
- 一個連線(TCP,UDP) 可以對應有多個管道
Netty
運用在那些領域?
- 分散式程序通訊
例如: hadoop、dubbo、akka , rocketmq等具有分散式功能的框架,底層RPC通訊都是基於netty實現的 - 遊戲伺服器開發