电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術(shù)文章
文章詳情頁

Java BIO,NIO,AIO總結(jié)

瀏覽:2日期:2022-08-25 10:57:02

Java 中的 BIO、NIO和 AIO 理解為是 Java 語言對操作系統(tǒng)的各種 IO 模型的封裝。程序員在使用這些 API 的時(shí)候,不需要關(guān)心操作系統(tǒng)層面的知識(shí),也不需要根據(jù)不同操作系統(tǒng)編寫不同的代碼。只需要使用Java的API就可以了。

在講 BIO,NIO,AIO 之前先來回顧一下這樣幾個(gè)概念:同步與異步,阻塞與非阻塞。 同步與異步

同步: 同步就是發(fā)起一個(gè)調(diào)用后,被調(diào)用者未處理完請求之前,調(diào)用不返回。 異步: 異步就是發(fā)起一個(gè)調(diào)用后,立刻得到被調(diào)用者的回應(yīng)表示已接收到請求,但是被調(diào)用者并沒有返回結(jié)果,此時(shí)我們可以處理其他的請求,被調(diào)用者通常依靠事件,回調(diào)等機(jī)制來通知調(diào)用者其返回結(jié)果。 同步和異步的區(qū)別最大在于異步的話調(diào)用者不需要等待處理結(jié)果,被調(diào)用者會(huì)通過回調(diào)等機(jī)制來通知調(diào)用者其返回結(jié)果。

阻塞和非阻塞

阻塞: 阻塞就是發(fā)起一個(gè)請求,調(diào)用者一直等待請求結(jié)果返回,也就是當(dāng)前線程會(huì)被掛起,無法從事其他任務(wù),只有當(dāng)條件就緒才能繼續(xù)。 非阻塞: 非阻塞就是發(fā)起一個(gè)請求,調(diào)用者不用一直等著結(jié)果返回,可以先去干其他事情。 舉個(gè)生活中簡單的例子,你媽媽讓你燒水,小時(shí)候你比較笨啊,在那里傻等著水開(同步阻塞)。等你稍微再長大一點(diǎn),你知道每次燒水的空隙可以去干點(diǎn)其他事,然后只需要時(shí)不時(shí)來看看水開了沒有(同步非阻塞)。后來,你們家用上了水開了會(huì)發(fā)出聲音的壺,這樣你就只需要聽到響聲后就知道水開了,在這期間你可以隨便干自己的事情,你需要去倒水了(異步非阻塞)。

BIO (Blocking I/O)

同步阻塞I/O模式,數(shù)據(jù)的讀取寫入必須阻塞在一個(gè)線程內(nèi)等待其完成。

傳統(tǒng) BIO

BIO通信(一請求一應(yīng)答)模型圖如下(圖源網(wǎng)絡(luò),原出處不明):

Java BIO,NIO,AIO總結(jié)

采用 BIO 通信模型 的服務(wù)端,通常由一個(gè)獨(dú)立的 Acceptor 線程負(fù)責(zé)監(jiān)聽客戶端的連接。我們一般通過在while(true) 循環(huán)中服務(wù)端會(huì)調(diào)用 accept() 方法等待接收客戶端的連接的方式監(jiān)聽請求,請求一旦接收到一個(gè)連接請求,就可以建立通信套接字在這個(gè)通信套接字上進(jìn)行讀寫操作,此時(shí)不能再接收其他客戶端連接請求,只能等待同當(dāng)前連接的客戶端的操作執(zhí)行完成, 不過可以通過多線程來支持多個(gè)客戶端的連接,如上圖所示。

如果要讓 BIO 通信模型 能夠同時(shí)處理多個(gè)客戶端請求,就必須使用多線程(主要原因是socket.accept()、socket.read()、socket.write() 涉及的三個(gè)主要函數(shù)都是同步阻塞的),也就是說它在接收到客戶端連接請求之后為每個(gè)客戶端創(chuàng)建一個(gè)新的線程進(jìn)行鏈路處理,處理完成之后,通過輸出流返回應(yīng)答給客戶端,線程銷毀。這就是典型的 一請求一應(yīng)答通信模型 。我們可以設(shè)想一下如果這個(gè)連接不做任何事情的話就會(huì)造成不必要的線程開銷,不過可以通過 線程池機(jī)制 改善,線程池還可以讓線程的創(chuàng)建和回收成本相對較低。使用FixedThreadPool 可以有效的控制了線程的最大數(shù)量,保證了系統(tǒng)有限的資源的控制,實(shí)現(xiàn)了N(客戶端請求數(shù)量):M(處理客戶端請求的線程數(shù)量)的偽異步I/O模型(N 可以遠(yuǎn)遠(yuǎn)大于 M),下面一節(jié)'偽異步 BIO'中會(huì)詳細(xì)介紹到。

我們再設(shè)想一下當(dāng)客戶端并發(fā)訪問量增加后這種模型會(huì)出現(xiàn)什么問題?

在 Java 虛擬機(jī)中,線程是寶貴的資源,線程的創(chuàng)建和銷毀成本很高,除此之外,線程的切換成本也是很高的。尤其在 Linux 這樣的操作系統(tǒng)中,線程本質(zhì)上就是一個(gè)進(jìn)程,創(chuàng)建和銷毀線程都是重量級的系統(tǒng)函數(shù)。如果并發(fā)訪問量增加會(huì)導(dǎo)致線程數(shù)急劇膨脹可能會(huì)導(dǎo)致線程堆棧溢出、創(chuàng)建新線程失敗等問題,最終導(dǎo)致進(jìn)程宕機(jī)或者僵死,不能對外提供服務(wù)。

偽異步 IO

為了解決同步阻塞I/O面臨的一個(gè)鏈路需要一個(gè)線程處理的問題,后來有人對它的線程模型進(jìn)行了優(yōu)化一一一后端通過一個(gè)線程池來處理多個(gè)客戶端的請求接入,形成客戶端個(gè)數(shù)M:線程池最大線程數(shù)N的比例關(guān)系,其中M可以遠(yuǎn)遠(yuǎn)大于N.通過線程池可以靈活地調(diào)配線程資源,設(shè)置線程的最大值,防止由于海量并發(fā)接入導(dǎo)致線程耗盡。

偽異步IO模型圖(圖源網(wǎng)絡(luò),原出處不明):

Java BIO,NIO,AIO總結(jié)

采用線程池和任務(wù)隊(duì)列可以實(shí)現(xiàn)一種叫做偽異步的 I/O 通信框架,它的模型圖如上圖所示。當(dāng)有新的客戶端接入時(shí),將客戶端的 Socket 封裝成一個(gè)Task(該任務(wù)實(shí)現(xiàn)java.lang.Runnable接口)投遞到后端的線程池中進(jìn)行處理,JDK 的線程池維護(hù)一個(gè)消息隊(duì)列和 N 個(gè)活躍線程,對消息隊(duì)列中的任務(wù)進(jìn)行處理。由于線程池可以設(shè)置消息隊(duì)列的大小和最大線程數(shù),因此,它的資源占用是可控的,無論多少個(gè)客戶端并發(fā)訪問,都不會(huì)導(dǎo)致資源的耗盡和宕機(jī)。

偽異步I/O通信框架采用了線程池實(shí)現(xiàn),因此避免了為每個(gè)請求都創(chuàng)建一個(gè)獨(dú)立線程造成的線程資源耗盡問題。不過因?yàn)樗牡讓尤匀皇峭阶枞腂IO模型,因此無法從根本上解決問題。

代碼示例

下面代碼中演示了BIO通信(一請求一應(yīng)答)模型。我們會(huì)在客戶端創(chuàng)建多個(gè)線程依次連接服務(wù)端并向其發(fā)送'當(dāng)前時(shí)間+:hello world',服務(wù)端會(huì)為每個(gè)客戶端線程創(chuàng)建一個(gè)線程來處理。代碼示例出自閃電俠的博客,原地址如下:

客戶端

/** * * @author 閃電俠 * @date 2018年10月14日 * @Description:客戶端 */public class IOClient { public static void main(String[] args) { // TODO 創(chuàng)建多個(gè)線程,模擬多個(gè)客戶端連接服務(wù)端 new Thread(() -> { try { Socket socket = new Socket('127.0.0.1', 3333); while (true) { try { socket.getOutputStream().write((new Date() + ': hello world').getBytes()); Thread.sleep(2000); } catch (Exception e) { } } } catch (IOException e) { } }).start(); }}

服務(wù)端

/** * @author 閃電俠 * @date 2018年10月14日 * @Description: 服務(wù)端 */public class IOServer { public static void main(String[] args) throws IOException { // TODO 服務(wù)端處理客戶端連接請求 ServerSocket serverSocket = new ServerSocket(3333); // 接收到客戶端連接請求之后為每個(gè)客戶端創(chuàng)建一個(gè)新的線程進(jìn)行鏈路處理 new Thread(() -> { while (true) { try { // 阻塞方法獲取新的連接 Socket socket = serverSocket.accept(); // 每一個(gè)新的連接都創(chuàng)建一個(gè)線程,負(fù)責(zé)讀取數(shù)據(jù) new Thread(() -> { try { int len; byte[] data = new byte[1024]; InputStream inputStream = socket.getInputStream(); // 按字節(jié)流方式讀取數(shù)據(jù) while ((len = inputStream.read(data)) != -1) {System.out.println(new String(data, 0, len)); } } catch (IOException e) { } }).start(); } catch (IOException e) { } } }).start(); }}

總結(jié)

在活動(dòng)連接數(shù)不是特別高(小于單機(jī)1000)的情況下,這種模型是比較不錯(cuò)的,可以讓每一個(gè)連接專注于自己的 I/O 并且編程模型簡單,也不用過多考慮系統(tǒng)的過載、限流等問題。線程池本身就是一個(gè)天然的漏斗,可以緩沖一些系統(tǒng)處理不了的連接或請求。但是,當(dāng)面對十萬甚至百萬級連接的時(shí)候,傳統(tǒng)的 BIO 模型是無能為力的。因此,我們需要一種更高效的 I/O 處理模型來應(yīng)對更高的并發(fā)量。

NIO (no blocking io 也叫 new io)

NIO 即非阻塞IO,是JDK 1.4 更新的api, 核心內(nèi)容是 將建立連接、數(shù)據(jù)可讀、可寫等事件交給了操作系統(tǒng)來維護(hù), 通過調(diào)用操作系統(tǒng)的 api (如:select、epoll等),來判斷當(dāng)前是否支持:可讀、可寫,如果當(dāng)前不可操作,那么直接返回,從而實(shí)現(xiàn)了非阻塞。 而不需要像 BIO 那樣每次去輪詢等待連接的建立以及數(shù)據(jù)的準(zhǔn)備是否完成。主要核心的模塊分以下幾類:

1. 緩沖區(qū)Buffer

一個(gè)特定基類(byte、short、int、long 等)的數(shù)據(jù)容器,用作在建立socket 連接之后的數(shù)據(jù)傳輸。通過 capacity, limit, position,mark 指針來實(shí)現(xiàn)數(shù)據(jù)的讀寫

get()、put() 方法為每個(gè)子類都具有的讀、寫數(shù)據(jù)的api方法,當(dāng)從當(dāng)前的 position 讀或?qū)懙耐瑫r(shí),position會(huì)增加 相應(yīng)讀寫的數(shù)據(jù)的長度。當(dāng)position 達(dá)到limit 之后,再次 get、put則會(huì)拋出異常

2. Channel 連接通道

一個(gè) channel 代表一個(gè)與“實(shí)體”的連接通道,如:硬件設(shè)備、文件、網(wǎng)絡(luò) socket 。通過連接通道可以使得客戶端-服務(wù)器互相傳輸數(shù)據(jù),因此通道也是全雙工的(因?yàn)槭墙⒃赥CP 傳輸層的協(xié)議上,因此具備全雙工的能力)。

JDK 中 channel 可以分為以下幾類:

SelectableChannel 用于 阻塞和非阻塞 socket 連接的通道FileChannel 用于文件操作,包括:reading, writing, mapping, and manipulating a file

3.Selector 多路復(fù)用選擇器

用于 SelectableChannel 的多路復(fù)用器,當(dāng)使用非阻塞的 socket 時(shí),需要將監(jiān)聽的通道 SelectableChannel 感興趣的事件注冊到 selector 多路復(fù)用器上(selector 實(shí)際上是通過調(diào)用操作系統(tǒng)層面的 select、epoll 方法來獲取當(dāng)前可用的時(shí)間)

與之對應(yīng)的感興趣的事件用 SelectionKey 來表示

OP_READ = 1 << 0; 可讀 OP_WRITE = 1 << 2; 可寫 OP_CONNECT = 1 << 3; // 完成連接 OP_ACCEPT = 1 << 4; // 接收連接

處理流程圖:

Java BIO,NIO,AIO總結(jié)

代碼示例:

通過 ServerSocketChannel 監(jiān)聽 8082 端口 設(shè)置為非阻塞 選擇與操作系統(tǒng)適配的選擇器,serverSocketChannel 的 OP_ACCEPT 事件注冊到 selector 選擇器上 當(dāng)OP_ACCEPT 事件觸發(fā)時(shí),將所有建立好的Socketchannel 連接的感興趣的事件(這里為 read事件)再次注冊到Selector 上

// 1.根據(jù)操作系統(tǒng)選擇適當(dāng)?shù)牡讓?io復(fù)用方法 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(8082)); //2.設(shè)置為非阻塞 serverSocketChannel.configureBlocking(false); //3.選擇與操作系統(tǒng)適配的選擇器 Selector selector = Selector.open(); //將 serverSocket 的OP_ACCEPT 事件注冊到 selector 選擇器上 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (true) { // 4.監(jiān)聽當(dāng)前連接建立情況 int select = selector.select(); if (select > 0) {//判斷連接業(yè)務(wù)類型Set<SelectionKey> set = selector.selectedKeys();Iterator<SelectionKey> iterator = set.iterator();while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); //建立連接 if (key.isAcceptable()) { ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); //通過 accept 方法獲取與 server端 已經(jīng)創(chuàng)建好的 socket連接 SocketChannel sc = ssc.accept(); //設(shè)置為非阻塞 sc.configureBlocking(false); //注冊感興趣的事件為 READ sc.register(selector, SelectionKey.OP_READ); } //可讀 else if (key.isReadable()) { SocketChannel socket = (SocketChannel) key.channel(); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); socket.read(byteBuffer); System.out.println(new String(byteBuffer.array(), StandardCharsets.UTF_8)); key.interestOps(SelectionKey.OP_WRITE); } //可寫 else if (key.isWritable()) { SocketChannel socket = (SocketChannel) key.channel(); socket.write(ByteBuffer.wrap('I’m receive your message'.getBytes(StandardCharsets.UTF_8))); socket.close(); System.out.println('連接關(guān)閉成功!'); }} } }

AIO(asynchronous io)

NIO 2.0引入了新的異步通道的概念,并提供了異步文件通道和異步套接字通道的實(shí)現(xiàn)。異步的套接字通道時(shí)真正的異步非阻塞I/O,對應(yīng)于UNIX網(wǎng)絡(luò)編程中的事件驅(qū)動(dòng)I/O(AIO)。他不需要過多的Selector對注冊的通道進(jìn)行輪詢即可實(shí)現(xiàn)異步讀寫,從而簡化了NIO的編程模型。

代碼示例

private static void server() throws IOException { //根據(jù)操作系統(tǒng)建立對應(yīng)的底層操作類 AsynchronousServerSocketChannel channel = AsynchronousServerSocketChannel.open(); channel.bind(new InetSocketAddress(8082)); while (true) { Future<AsynchronousSocketChannel> future = channel.accept(); try {AsynchronousSocketChannel asc = future.get();System.out.println('建立連接成功');Future<Integer> write = asc.write(ByteBuffer.wrap('Now let’s exchange datas'.getBytes(StandardCharsets.UTF_8)));while (!write.isDone()) { TimeUnit.SECONDS.sleep(2);}System.out.println('發(fā)送數(shù)據(jù)完成');asc.close(); } catch (Exception e) {e.printStackTrace(); } } } private static void client() throws Exception { AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open(); Future<Void> future = socketChannel.connect(new InetSocketAddress(8082)); while (!future.isDone()) { TimeUnit.SECONDS.sleep(2); } ByteBuffer buffer = ByteBuffer.allocate(1024); Future<Integer> read = socketChannel.read(buffer); while (!read.isDone()) { TimeUnit.SECONDS.sleep(2); } System.out.println('接收服務(wù)器數(shù)據(jù):' + new String(buffer.array(), 0, read.get())); }

以上就是Java BIO,NIO,AIO總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于Java BIO,NIO,AIO的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 托利多电子平台秤-高精度接线盒-托利多高精度电子秤|百科 | 喷播机厂家_二手喷播机租赁_水泥浆洒布机-河南青山绿水机电设备有限公司 | 无压烧结银_有压烧结银_导电银胶_导电油墨_导电胶-善仁(浙江)新材料 | 海外整合营销-独立站营销-社交媒体运营_广州甲壳虫跨境网络服务 焊管生产线_焊管机组_轧辊模具_焊管设备_焊管设备厂家_石家庄翔昱机械 | 防腐储罐_塑料储罐_PE储罐厂家_淄博富邦滚塑防腐设备科技有限公司 | 二手电脑回收_二手打印机回收_二手复印机回_硒鼓墨盒回收-广州益美二手电脑回收公司 | 物联网卡_物联网卡购买平台_移动物联网卡办理_移动联通电信流量卡通信模组采购平台? | led冷热冲击试验箱_LED高低温冲击试验箱_老化试验箱-爱佩百科 | 对夹式止回阀_对夹式蝶形止回阀_对夹式软密封止回阀_超薄型止回阀_不锈钢底阀-温州上炬阀门科技有限公司 | 生产加气砖设备厂家很多,杜甫机械加气砖设备价格公道 | 快速门厂家-快速卷帘门-工业快速门-硬质快速门-西朗门业 | 防水套管厂家_刚性防水套管_柔性防水套管_不锈钢防水套管-郑州中泰管道 | H型钢切割机,相贯线切割机,数控钻床,数控平面钻,钢结构设备,槽钢切割机,角钢切割机,翻转机,拼焊矫一体机 | 北京印刷厂_北京印刷_北京印刷公司_北京印刷厂家_北京东爵盛世印刷有限公司 | 电机保护器-电动机综合保护器-上海硕吉电器有限公司 | 双菱电缆-广州电缆厂_广州电缆厂有限公司| 二手注塑机回收_旧注塑机回收_二手注塑机买卖 - 大鑫二手注塑机 二手光谱仪维修-德国OBLF光谱仪|进口斯派克光谱仪-热电ARL光谱仪-意大利GNR光谱仪-永晖检测 | 细石混凝土泵_厂家_价格-烟台九达机械有限公司 | 佛山市钱丰金属不锈钢蜂窝板定制厂家|不锈钢装饰线条|不锈钢屏风| 电梯装饰板|不锈钢蜂窝板不锈钢工艺板材厂家佛山市钱丰金属制品有限公司 | 德州网站制作 - 网站建设设计 - seo排名优化 -「两山建站」 | 东风体检车厂家_公共卫生体检车_医院体检车_移动体检车-锦沅科贸 | 绿萝净除甲醛|深圳除甲醛公司|测甲醛怎么收费|培训机构|电影院|办公室|车内|室内除甲醛案例|原理|方法|价格立马咨询 | 氢氧化钙设备_厂家-淄博工贸有限公司 | 珠光砂保温板-一体化保温板-有釉面发泡陶瓷保温板-杭州一体化建筑材料 | 干法制粒机_智能干法制粒机_张家港市开创机械制造有限公司 | 艾默生变频器,艾默生ct,变频器,ct驱动器,广州艾默生变频器,供水专用变频器,风机变频器,电梯变频器,艾默生变频器代理-广州市盟雄贸易有限公司官方网站-艾默生变频器应用解决方案服务商 | 东莞市天进机械有限公司-钉箱机-粘箱机-糊箱机-打钉机认准东莞天进机械-厂家直供更放心! | 罗氏牛血清白蛋白,罗氏己糖激酶-上海嵘崴达实业有限公司 | 档案密集架,移动密集架,手摇式密集架,吉林档案密集架-厂家直销★价格公道★质量保证 | 东莞工厂厂房装修_无尘车间施工_钢结构工程安装-广东集景建筑装饰设计工程有限公司 | 超声波成孔成槽质量检测仪-压浆机-桥梁预应力智能张拉设备-上海硕冠检测设备有限公司 | 量子管通环-自清洗过滤器-全自动反冲洗过滤器-沼河浸过滤器 | 山东聚盛新型材料有限公司-纳米防腐隔热彩铝板和纳米防腐隔热板以及钛锡板、PVDF氟膜板供应商 | 私人别墅家庭影院系统_家庭影院音响_家庭影院装修设计公司-邦牛影音 | 天津仓库出租网-天津电商仓库-天津云仓一件代发-【博程云仓】 | 中式装修设计_室内中式装修_【云臻轩】中式设计机构 | 压砖机_电动螺旋压力机_粉末成型压力机_郑州华隆机械tel_0371-60121717 | 密集架|电动密集架|移动密集架|黑龙江档案密集架-大量现货厂家销售 | 天津蒸汽/热水锅炉-电锅炉安装维修直销厂家-天津鑫淼暖通设备有限公司 | 散热器-电子散热器-型材散热器-电源散热片-镇江新区宏图电子散热片厂家 | 炭黑吸油计_测试仪,单颗粒子硬度仪_ASTM标准炭黑自销-上海贺纳斯仪器仪表有限公司(HITEC中国办事处) |