1. 程式人生 > 其它 >java nio aio bio概念

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事件所採用的方式

  • 同步

    1. 應用程式直接參與io讀寫的操作

    2. 會阻塞在某個方法上等待io事件的完成(阻塞io事件 或者 通過輪詢方式)

      • 阻塞io事件

        不能做自己的事情,一直阻塞執行緒

      • IO事件輪詢方式(多路複用,Select模式)

        讀寫事件交給一個單獨的(select)執行緒來處理,並完成io事件的註冊功能 ,然後不斷的輪詢讀寫緩衝區看資料是否準備好,有資料通知我們的讀寫執行緒 。這樣以前的讀寫執行緒可以做其它事情 ,因為這個時候阻塞的不是所有的io執行緒,而是select執行緒 (select 相當於一個管家)

        但是它還是同步的,因為真正的io操作不是完全交給作業系統的,應用程式要參與

      • 例子(把select比做管家,還有客人和主人):

        當【客人】來拜訪【主人】的時候,先找到【管家】,【管家】得到這個註冊資訊後,跟【主人】說:我這裡來了一個或者多個【客人】,他們需要【主人】給他們某某東西 。這個時候【客人】可以去做其它事情,比如看看花園 。當【管家】得知【主人】準備好東西后,他就去找對應的某人 告訴這位【客人】主人給他某樣東西 ,這個時候阻塞是發生在 【管家】不是【客人】

  • 非同步

    1. 所有的io操作交給OS處理

    2. 可以去做其它事情,並不需要去完成真正的io操作,當作業系統完成io後,給我們應用程式一個通知就行

  • 例子(來源於網路)阻塞和非阻塞,同步和非同步

    故事:老王燒開水。

    出場人物:老張,水壺兩把(普通水壺,簡稱水壺;會響的水壺,簡稱響水壺)。

    老王想了想,有好幾種等待方式

    1. 老王用水壺煮水,並且站在那裡不管水開沒開,每隔一定時間看看水開了沒。-同步阻塞

    老王想了想,這種方法不夠聰明。

    1. 老王還是用水壺煮水,不再傻傻的站在那裡看水開,跑去寢室上網但是還是會每隔一段時間過來看看水開了沒有,水沒有開就走人。-同步非阻塞

    老王想了想,現在的方法聰明瞭些,但是還是不夠好。

    1. 老王這次使用高大上的響水壺來煮水,站在那裡但是不會再每隔一段時間去看水開,而是等水開了,水壺會自動的通知他。-非同步阻塞

    老王想了想,不會呀,既然水壺可以通知我,那我為什麼還要傻傻的站在那裡等呢,嗯,得換個方法。

    1. 老王還是使用響水壺煮水,跑到客廳上網去,等著響水壺自己把水煮熟了以後通知他。-非同步非阻塞

    老王豁然,這下感覺輕鬆了很多。

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

運用在那些領域?

  1. 分散式程序通訊
    例如: hadoop、dubbo、akka , rocketmq等具有分散式功能的框架,底層RPC通訊都是基於netty實現的
  2. 遊戲伺服器開發

詳細的另外的文章再寫吧