javanio,javanio和io的區別

本文目錄一覽:

java nio 開發實例

首先了解下所謂的java nio是個什麼東西!

傳統的並髮型伺服器設計是利用阻塞型網路I/O 以多線程的模式來實現的 然而由

於系統常常在進行網路讀寫時處於阻塞狀態 會大大影響系統的性能 自Java 開始引入

了NIO(新I/O) API 通過使用非阻塞型I/O 實現流暢的網路讀寫操作 為開發高性能並發

型伺服器程序提供了一個很好的解決方案 這就是java nio

首先來看下傳統的阻塞型網路 I/O的不足

Java 平台傳統的I/O 系統都是基於Byte(位元組)和Stream(數據流)的 相應的I/O 操

作都是阻塞型的 所以伺服器程序也採用阻塞型I/O 進行數據的讀 寫操作 本文以TCP

長連接模式來討論並髮型伺服器的相關設計 為了實現伺服器程序的並發性要求 系統由一

個單獨的主線程來監聽用戶發起的連接請求 一直處於阻塞狀態 當有用戶連接請求到來時

程序都會啟一個新的線程來統一處理用戶數據的讀 寫操作

這種模式的優點是簡單 實用 易管理 然而缺點也是顯而易見的 由於是為每一個客

戶端分配一個線程來處理輸入 輸出數據 其線程與客戶機的比例近似為 隨著線程

數量的不斷增加 伺服器啟動了大量的並發線程 會大大加大系統對線程的管理開銷 這將

成為吞吐量瓶頸的主要原因 其次由於底層的I/O 操作採用的同步模式 I/O 操作的阻塞管

理粒度是以服務於請求的線程為單位的 有可能大量的線程會閑置 處於盲等狀態 造成I/O

資源利用率不高 影響整個系統的性能

對於並髮型伺服器 系統用在阻塞型I/O 等待和線程間切換的時間遠遠多於CPU 在內

存中處理數據的時間 因此傳統的阻塞型I/O 已經成為制約系統性能的瓶頸 Java 版本

後推出的NIO 工具包 提供了非阻塞型I/O 的非同步輸入輸出機制 為提高系統的性能提供

了可實現的基礎機制

NIO 包及工作原理

針對傳統I/O 工作模式的不足 NIO 工具包提出了基於Buffer(緩衝區) Channel(通

道) Selector(選擇器)的新模式 Selector(選擇器) 可選擇的Channel(通道)和

SelectionKey(選擇鍵)配合起來使用 可以實現並發的非阻塞型I/O 能力

NIO 工具包的成員

Buffer(緩衝器)

Buffer 類是一個抽象類 它有 個子類分別對應於七種基本的數據類型 ByteBuffer

CharBuffer DoubleBuffer FloatBuffer IntBuffer LongBuffer 和ShortBuffer 每一個Buffer

對象相當於一個數據容器 可以把它看作內存中的一個大的數組 用來存儲和提取所有基本

類型(boolean 型除外)的數據 Buffer 類的核心是一塊內存區 可以直接對其執行與內存有關

的操作 利用操作系統特性和能力提高和改善Java 傳統I/O 的性能

Channel(通道)

Channel 被認為是NIO 工具包的一大創新點 是(Buffer)緩衝器和I/O 服務之間的通道

具有雙向性 既可以讀入也可以寫出 可以更高效的傳遞數據 我們這裡主要討論

ServerSocketChannel 和SocketChannel 它們都繼承了SelectableChannel 是可選擇的通道

分別可以工作在同步和非同步兩種方式下(這裡的可選擇不是指可以選擇兩種工作方式 而是

指可以有選擇的註冊自己感興趣的事件) 當通道工作在同步方式時 它的功能和編程方法

與傳統的ServerSocket Socket 對象相似 當通道工作在非同步工作方式時 進行輸入輸出處

理不必等到輸入輸出完畢才返回 並且可以將其感興趣的(如 接受操作 連接操作 讀出

操作 寫入操作)事件註冊到Selector 對象上 與Selector 對象協同工作可以更有效率的支

持和管理並發的網路套接字連接

Selector(選擇器)和SelectionKey(選擇鍵)

各類 Buffer 是數據的容器對象 各類Channel 實現在各類Buffer 與各類I/O 服務間傳輸

數據 Selector 是實現並髮型非阻塞I/O 的核心 各種可選擇的通道將其感興趣的事件註冊

到Selector 對象上 Selector 在一個循環中不斷輪循監視這各些註冊在其上的Socket 通道

SelectionKey 類則封裝了SelectableChannel 對象在Selector 中的註冊信息 當Selector 監測

到在某個註冊的SelectableChannel 上發生了感興趣的事件時 自動激活產生一個SelectionKey

對象 在這個對象中記錄了哪一個SelectableChannel 上發生了哪種事件 通過對被激活的

SelectionKey 的分析 外界可以知道每個SelectableChannel 發生的具體事件類型 進行相應的

處理

NIO 工作原理

通過上面的討論 我們可以看出在並髮型伺服器程序中使用NIO 實際上是通過網路事

件驅動模型實現的 我們應用Select 機制 不用為每一個客戶端連接新啟線程處理 而是將

其註冊到特定的Selector 對象上 這就可以在單線程中利用Selector 對象管理大量並發的網

絡連接 更好的利用了系統資源 採用非阻塞I/O 的通信方式 不要求阻塞等待I/O 操作完

成即可返回 從而減少了管理I/O 連接導致的系統開銷 大幅度提高了系統性能

當有讀或寫等任何註冊的事件發生時 可以從Selector 中獲得相應的

SelectionKey 從SelectionKey 中可以找到發生的事件和該事件所發生的具體的

SelectableChannel 以獲得客戶端發送過來的數據 由於在非阻塞網路I/O 中採用了事件觸

發機制 處理程序可以得到系統的主動通知 從而可以實現底層網路I/O 無阻塞 流暢地讀

寫 而不像在原來的阻塞模式下處理程序需要不斷循環等待 使用NIO 可以編寫出性能更

好 更易擴展的並髮型伺服器程序

並髮型伺服器程序的實現代碼

應用 NIO 工具包 基於非阻塞網路I/O 設計的並髮型伺服器程序與以往基於阻塞I/O 的

實現程序有很大不同 在使用非阻塞網路I/O 的情況下 程序讀取數據和寫入數據的時機不

是由程序員控制的 而是Selector 決定的 下面便給出基於非阻塞網路I/O 的並髮型伺服器

程序的核心代碼片段

import java io * //引入Java io包

import * //引入包

import java nio channels * //引入Java nio channels包

import java util * //引入Java util包

public class TestServer implements Runnable

{

/**

* 伺服器Channel對象 負責接受用戶連接

*/

private ServerSocketChannel server

/**

* Selector對象 負責監控所有的連接到伺服器的網路事件的發生

*/

private Selector selector

/**

* 總的活動連接數

*/

private int activeSockets

/**

* 伺服器Channel綁定的埠號

*/

private int port

/**

*

* 構造函數

*/

public TestServer()throws IOException

{

activeSockets=

port= //初始化伺服器Channel綁定的埠號為

selector= Selector open() //初始化Selector對象

server=ServerSocketChannel open() //初始化伺服器Channel對象

ServerSocket socket=server socket() //獲取伺服器Channel對應的//ServerSocket對象

socket bind(new InetSocketAddress(port)) //把Socket綁定到監聽埠 上

nfigureBlocking(false) //將伺服器Channel設置為非阻塞模式

server register(selector SelectionKey OP_ACCEPT) //將伺服器Channel註冊到

Selector對象 並指出伺服器Channel所感興趣的事件為可接受請求操作

}

public void run()

{

while(true)

{

try

{

/**

*應用Select機制輪循是否有用戶感興趣的新的網路事件發生 當沒有

* 新的網路事件發生時 此方法會阻塞 直到有新的網路事件發生為止

*/

selector select()

}

catch(IOException e)

{

continue //當有異常發生時 繼續進行循環操作

}

/**

* 得到活動的網路連接選擇鍵的集合

*/

SetSelectionKey keys=selector selectedKeys()

activeSockets=keys size() //獲取活動連接的數目

if(activeSockets== )

{

continue //如果連接數為 則繼續進行循環操作

}

/**

/**

* 應用For—Each循環遍歷整個選擇鍵集合

*/

for(SelectionKey key :keys)

{

/**

* 如果關鍵字狀態是為可接受 則接受連接 註冊通道 以接受更多的*

事件 進行相關的伺服器程序處理

*/

if(key isAcceptable())

{

doServerSocketEvent(key)

continue

}

/**

* 如果關鍵字狀態為可讀 則說明Channel是一個客戶端的連接通道

* 進行相應的讀取客戶端數據的操作

*/

if(key isReadable())

{

doClientReadEvent(key)

continue

}

/**

* 如果關鍵字狀態為可寫 則也說明Channel是一個客戶端的連接通道

* 進行相應的向客戶端寫數據的操作

*/

if(key isWritable())

{

doClinetWriteEvent(key)

continue

}

}

}

}

/**

* 處理伺服器事件操作

* @param key 伺服器選擇鍵對象

*/

private void doServerSocketEvent(SelectionKey key)

{

SocketChannel client=null

try

{

ServerSocketChannel server=(ServerSocketChannel)key channel()

client=server accept()

if(client==null)

{

return

}

nfigureBlocking(false) //將客戶端Channel設置為非阻塞型

/**

/**

* 將客戶端Channel註冊到Selector對象上 並且指出客戶端Channel所感

* 興趣的事件為可讀和可寫

*/

client register(selector SelectionKey OP_READ|SelectionKey OP_READ)

}catch(IOException e)

{

try

{

client close()

}catch(IOException e ){}

}

}

/**

* 進行向客戶端寫數據操作

* @param key 客戶端選擇鍵對象

*/

private void doClinetWriteEvent(SelectionKey key)

{

代碼實現略

}

/**

* 進行讀取客戶短數據操作

* @param key 客戶端選擇鍵對象

*/

private void doClientReadEvent(SelectionKey key)

{

代碼實現略

}

}

從上面對代碼可以看出 使用非阻塞性I/O進行並髮型伺服器程序設計分三個部分

向Selector對象註冊感興趣的事件 從Selector中獲取所感興趣的事件 根據不同的事件進

行相應的處理

結語

通過使用NIO 工具包進行並髮型伺服器程序設計 一個或者很少幾個Socket 線程就可

以處理成千上萬個活動的Socket 連接 大大降低了伺服器端程序的開銷 同時網路I/O 採取

非阻塞模式 線程不再在讀或寫時阻塞 操作系統可以更流暢的讀寫數據並可以更有效地向

CPU 傳遞數據進行處理 以便更有效地提高系統的性能

看到這裡相信你看了不止 分鐘了吧   我說 分鐘其實就是想讓大家能夠輕鬆的讀下去(雞蛋 )

好了 到這裡大家應該對java nio有個初步的了解了吧~~~

lishixinzhi/Article/program/Java/hx/201311/27190

Java中IO與NIO的區別和使用場景

在java2以前,傳統的socket IO中,需要為每個連接創建一個線程,當並發的連接數量非常巨大時,線程所佔用的棧內存和CPU線程切換的開銷將非常巨大。java5以後使用NIO,不再需要為每個線程創建單獨的線程,可以用一個含有限數量線程的線程池,甚至一個線程來為任意數量的連接服務。由於線程數量小於連接數量,所以每個線程進行IO操作時就不能阻塞,如果阻塞的話,有些連接就得不到處理,NIO提供了這種非阻塞的能力。

NIO 設計背後的基石:反應器模式,用於事件多路分離和分派的體系結構模式。

反應器(Reactor):用於事件多路分離和分派的體系結構模式

通常的,對一個文件描述符指定的文件或設備, 有兩種工作方式: 阻塞 與非阻塞 。所謂阻塞方式的意思是指, 當試圖對該文件描述符進行讀寫時, 如果當時沒有東西可讀,或者暫時不可寫, 程序就進入等待 狀態, 直到有東西可讀或者可寫為止。而對於非阻塞狀態, 如果沒有東西可讀, 或者不可寫, 讀寫函數馬上返回, 而不會等待 。

一種常用做法是:每建立一個Socket連接時,同時創建一個新線程對該Socket進行單獨通信(採用阻塞的方式通信)。這種方式具有很高的響應速度,並且控制起來也很簡單,在連接數較少的時候非常有效,但是如果對每一個連接都產生一個線程的無疑是對系統資源的一種浪費,如果連接數較多將會出現資源不足的情況。

另一種較高效的做法是:伺服器端保存一個Socket連接列表,然後對這個列表進行輪詢,如果發現某個Socket埠上有數據可讀時(讀就緒),則調用該socket連接的相應讀操作;如果發現某個 Socket埠上有數據可寫時(寫就緒),則調用該socket連接的相應寫操作;如果某個埠的Socket連接已經中斷,則調用相應的析構方法關閉該埠。這樣能充分利用伺服器資源,效率得到了很大提高。

傳統的阻塞式IO,每個連接必須要開一個線程來處理,並且沒處理完線程不能退出。

非阻塞式IO,由於基於反應器模式,用於事件多路分離和分派的體系結構模式,所以可以利用線程池來處理。事件來了就處理,處理完了就把線程歸還。而傳統阻塞方式不能使用線程池來處理,假設當前有10000個連接,非阻塞方式可能用1000個線程的線程池就搞定了,而傳統阻塞方式就需要開10000個來處理。如果連接數較多將會出現資源不足的情況。非阻塞的核心優勢就在這裡。

為什麼會這樣,下面就對他們做進一步細緻具體的分析:

首先,我們來分析傳統阻塞式IO的瓶頸在哪裡。在連接數不多的情況下,傳統IO編寫容易方便使用。但是隨著連接數的增多,問題傳統IO就不行了。因為前面說過,傳統IO處理每個連接都要消耗一個線程,而程序的效率當線程數不多時是隨著線程數的增加而增加,但是到一定的數量之後,是隨著線程數的增加而減少。這裡我們得出結論,傳統阻塞式IO的瓶頸在於不能處理過多的連接。

然後,非阻塞式IO的出現的目的就是為了解決這個瓶頸。而非阻塞式IO是怎麼實現的呢?非阻塞IO處理連接的線程數和連接數沒有聯繫,也就是說處理 10000個連接非阻塞IO不需要10000個線程,你可以用1000個也可以用2000個線程來處理。因為非阻塞IO處理連接是非同步的。當某個鏈接發送請求到伺服器,伺服器把這個連接請求當作一個請求”事件”,並把這個”事件”分配給相應的函數處理。我們可以把這個處理函數放到線程中去執行,執行完就把線程歸還。這樣一個線程就可以非同步的處理多個事件。而阻塞式IO的線程的大部分時間都浪費在等待請求上了。

所謂阻塞式IO流,就是指在從數據流當中讀寫數據的的時候,阻塞當前線程,直到IO流可以

重新使用為止,你也可以使用流的avaliableBytes()函數看看當前流當中有多少位元組可以讀取,這樣

就不會再阻塞了。

介紹一下Java NIO,NIO讀取文件都有哪些方法

NIO也就是New I/O,是一組擴展Java IO操作的API集, 於Java 1.4起被引入,Java 7中NIO又提供了一些新的文件系統API,叫NIO2.

NIO2提供兩種主要的文件讀取方法:

使用buffer和channel類

使用Path 和 File 類

NIO讀取文件有以下三種方式:

1. 舊的NIO方式,使用BufferedReader

import java.io.BufferedReader;

import java.io.FileReader;

import java.io.IOException;

public class WithoutNIOExample

{

public static void main(String[] args)

{

BufferedReader br = null;

String sCurrentLine = null;

try

{

br = new BufferedReader(

new FileReader(“test.txt”));

while ((sCurrentLine = br.readLine()) != null)

{

System.out.println(sCurrentLine);

}

}

catch (IOException e)

{

e.printStackTrace();

}

finally

{

try

{

if (br != null)

br.close();

} catch (IOException ex)

{

ex.printStackTrace();

}

}

}

}

2. 使用buffer讀取小文件

import java.io.IOException;

import java.io.RandomAccessFile;

import java.nio.ByteBuffer;

import java.nio.channels.FileChannel;

public class ReadFileWithFileSizeBuffer

{

public static void main(String args[])

{

try

{

RandomAccessFile aFile = new RandomAccessFile(

“test.txt”,”r”);

FileChannel inChannel = aFile.getChannel();

long fileSize = inChannel.size();

ByteBuffer buffer = ByteBuffer.allocate((int) fileSize);

inChannel.read(buffer);

buffer.rewind();

buffer.flip();

for (int i = 0; i fileSize; i++)

{

System.out.print((char) buffer.get());

}

inChannel.close();

aFile.close();

}

catch (IOException exc)

{

System.out.println(exc);

System.exit(1);

}

}

}

3. 分塊讀取大文件

import java.io.IOException;

import java.io.RandomAccessFile;

import java.nio.ByteBuffer;

import java.nio.channels.FileChannel;

public class ReadFileWithFixedSizeBuffer

{

public static void main(String[] args) throws IOException

{

RandomAccessFile aFile = new RandomAccessFile

(“test.txt”, “r”);

FileChannel inChannel = aFile.getChannel();

ByteBuffer buffer = ByteBuffer.allocate(1024);

while(inChannel.read(buffer) 0)

{

buffer.flip();

for (int i = 0; i buffer.limit(); i++)

{

System.out.print((char) buffer.get());

}

buffer.clear(); // do something with the data and clear/compact it.

}

inChannel.close();

aFile.close();

}

}

4. 使用MappedByteBuffer讀取文件

import java.io.RandomAccessFile;

import java.nio.MappedByteBuffer;

import java.nio.channels.FileChannel;

public class ReadFileWithMappedByteBuffer

{

public static void main(String[] args) throws IOException

{

RandomAccessFile aFile = new RandomAccessFile

(“test.txt”, “r”);

FileChannel inChannel = aFile.getChannel();

MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());

buffer.load();?

for (int i = 0; i buffer.limit(); i++)

{

System.out.print((char) buffer.get());

}

buffer.clear(); // do something with the data and clear/compact it.

inChannel.close();

aFile.close();

}

}

Java NIO和IO的區別

Java

NIO和IO的主要區別如下:

1.NIO

的創建目的是為了讓

Java

程序員可以實現高速

I/O

而無需編寫自定義的本機代碼。NIO

將最耗時的

I/O

操作(即填充和提取緩衝區)轉移回操作系統,因而可以極大地提高速度。傳統的IO操作屬於阻塞型,嚴重影響程序的運行速度。

2,。流與塊的比較。原來的

I/O

庫(在

java.io.*中)

NIO

最重要的區別是數據打包和傳輸的方式。正如前面提到的,原來的

I/O

以流的方式處理數據,而

NIO

以塊的方式處理數據。

面向流

I/O

系統一次一個位元組地處理數據。一個輸入流產生一個位元組的數據,一個輸出流消費一個位元組的數據。為流式數據創建過濾器非常容易。鏈接幾個過濾器,以便每個過濾器只負責單個複雜處理機制的一部分,這樣也是相對簡單的。不利的一面是,面向流的

I/O

通常相當慢。

3.一個

面向塊

I/O

系統以塊的形式處理數據。每一個操作都在一步中產生或者消費一個數據塊。按塊處理數據比按(流式的)位元組處理數據要快得多。但是面向塊的

I/O

缺少一些面向流的

I/O

所具有的優雅性和簡單性。

原創文章,作者:XGIR,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/140310.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
XGIR的頭像XGIR
上一篇 2024-10-04 00:23
下一篇 2024-10-04 00:23

相關推薦

  • Python中new和init的區別

    new和init都是Python中常用的魔法方法,它們分別負責對象的創建和初始化,本文將從多個角度詳細闡述它們的區別。 一、創建對象 new方法是用來創建一個對象的,它是一個類級別…

    編程 2025-04-29
  • Sublime Test與Python的區別

    Sublime Text是一款流行的文本編輯器,而Python是一種廣泛使用的編程語言。雖然Sublime Text可以用於編寫Python代碼,但它們之間有很多不同之處。接下來從…

    編程 2025-04-29
  • Shell腳本與Python腳本的區別

    本文將從多個方面對Shell腳本與Python腳本的區別做詳細的闡述。 一、語法差異 Shell腳本和Python腳本的語法存在明顯差異。 Shell腳本是一種基於字元命令行的語言…

    編程 2025-04-29
  • Python中while語句和for語句的區別

    while語句和for語句是Python中兩種常見的循環語句,它們都可以用於重複執行一段代碼。然而,它們的語法和適用場景有所不同。本文將從多個方面詳細闡述Python中while語…

    編程 2025-04-29
  • Web程序和桌面程序的區別

    Web程序和桌面程序都是進行軟體開發的方式,但是它們之間存在很大的區別。本文將從多角度進行闡述。 一、運行方式 Web程序運行於互聯網上,用戶可以通過使用瀏覽器來訪問它。而桌面程序…

    編程 2025-04-29
  • TensorFlow和Python的區別

    TensorFlow和Python是現如今最受歡迎的機器學習平台和編程語言。雖然兩者都處於機器學習領域的主流陣營,但它們有很多區別。本文將從多個方面對TensorFlow和Pyth…

    編程 2025-04-28
  • 麥語言與Python的區別

    麥語言和Python都是非常受歡迎的編程語言。它們各自有自己的優缺點和適合的應用場景。本文將從語言特性、語法、生態系統等多個方面,對麥語言和Python進行詳細比較和闡述。 一、語…

    編程 2025-04-28
  • MySQL bigint與long的區別

    本文將從數據類型定義、存儲空間、數據範圍、計算效率、應用場景五個方面詳細闡述MySQL bigint與long的區別。 一、數據類型定義 bigint在MySQL中是一種有符號的整…

    編程 2025-04-28
  • Python與C語言的區別和聯繫

    Python與C語言是兩種常用的編程語言,雖然兩者都可以用於編寫軟體程序,但是它們之間有很多不同之處。本文將從多個方面對Python與C語言的區別和聯繫進行詳細的闡述。 一、語法特…

    編程 2025-04-28
  • gateway io.netty.buffer.poolchunk

    在本文中,我們將深入探討Netty中的一個基礎組件——PoolChunk,它是Netty中ByteBuf的一個關鍵實現,負責對ByteBuf進行緩存和管理。我們將從多個方面對該組件…

    編程 2025-04-28

發表回復

登錄後才能評論