亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java?NIO與IO的區(qū)別以及比較

 更新時(shí)間:2022年09月19日 14:30:20   作者:是溫度呀???????  
這篇文章主要介紹了Java?NIO與IO的區(qū)別以及比較,文章通過圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下

前言

傳統(tǒng)的socket IO中,需要為每個(gè)連接創(chuàng)建一個(gè)線程,當(dāng)并發(fā)的連接數(shù)量非常巨大時(shí),線程所占用的棧內(nèi)存和CPU線程切換的開銷將非常巨大。使用NIO,不再需要為每個(gè)線程創(chuàng)建單獨(dú)的線程,可以用一個(gè)含有限數(shù)量線程的線程池,甚至一個(gè)線程來為任意數(shù)量的連接服務(wù)。由于線程數(shù)量小于連接數(shù)量,所以每個(gè)線程進(jìn)行IO操作時(shí)就不能阻塞,如果阻塞的話,有些連接就得不到處理,NIO提供了這種非阻塞的能力。

小量的線程如何同時(shí)為大量連接服務(wù)呢,答案就是就緒選擇。這就好比到餐廳吃飯,每來一桌客人,都有一個(gè)服務(wù)員專門為你服務(wù),從你到餐廳到結(jié)帳走人,這樣方式的好處是服務(wù)質(zhì)量好,一對一的服務(wù),VIP啊,可是缺點(diǎn)也很明顯,成本高,如果餐廳生意好,同時(shí)來100桌客人,就需要100個(gè)服務(wù)員,那老板發(fā)工資的時(shí)候得心痛死了,這就是傳統(tǒng)的一個(gè)連接一個(gè)線程的方式。

老板是什么人啊,精著呢。這老板就得捉摸怎么能用10個(gè)服務(wù)員同時(shí)為100桌客人服務(wù)呢,老板就發(fā)現(xiàn),服務(wù)員在為客人服務(wù)的過程中并不是一直都忙著,客人點(diǎn)完菜,上完菜,吃著的這段時(shí)間,服務(wù)員就閑下來了,可是這個(gè)服務(wù)員還是被這桌客人占用著,不能為別的客人服務(wù),用華為領(lǐng)導(dǎo)的話說,就是工作不飽滿。那怎么把這段閑著的時(shí)間利用起來呢。這餐廳老板就想了一個(gè)辦法,讓一個(gè)服務(wù)員(前臺)專門負(fù)責(zé)收集客人的需求,登記下來,比如有客人進(jìn)來了、客人點(diǎn)菜了,客人要結(jié)帳了,都先記錄下來按順序排好。每個(gè)服務(wù)員到這里領(lǐng)一個(gè)需求,比如點(diǎn)菜,就拿著菜單幫客人點(diǎn)菜去了。點(diǎn)好菜以后,服務(wù)員馬上回來,領(lǐng)取下一個(gè)需求,繼續(xù)為別人客人服務(wù)去了。這種方式服務(wù)質(zhì)量就不如一對一的服務(wù)了,當(dāng)客人數(shù)據(jù)很多的時(shí)候可能需要等待。但好處也很明顯,由于在客人正吃飯著的時(shí)候服務(wù)員不用閑著了,服務(wù)員這個(gè)時(shí)間內(nèi)可以為其他客人服務(wù)了,原來10個(gè)服務(wù)員最多同時(shí)為10桌客人服務(wù),現(xiàn)在可能為50桌,60客人服務(wù)了。

這種服務(wù)方式跟傳統(tǒng)的區(qū)別有兩個(gè):

  • 1、增加了一個(gè)角色,要有一個(gè)專門負(fù)責(zé)收集客人需求的人。NIO里對應(yīng)的就是Selector。
  • 2、由阻塞服務(wù)方式改為非阻塞服務(wù)了,客人吃著的時(shí)候服務(wù)員不用一直侯在客人旁邊了。傳統(tǒng)的IO操作,比如read(),當(dāng)沒有數(shù)據(jù)可讀的時(shí)候,線程一直阻塞被占用,直到數(shù)據(jù)到來。NIO中沒有數(shù)據(jù)可讀時(shí),read()會立即返回0,線程不會阻塞。

NIO中,客戶端創(chuàng)建一個(gè)連接后,先要將連接注冊到Selector,相當(dāng)于客人進(jìn)入餐廳后,告訴前臺你要用餐,前臺會告訴你你的桌號是幾號,然后你就可能到那張桌子坐下了,SelectionKey就是桌號。當(dāng)某一桌需要服務(wù)時(shí),前臺就記錄哪一桌需要什么服務(wù),比如1號桌要點(diǎn)菜,2號桌要結(jié)帳,服務(wù)員從前臺取一條記錄,根據(jù)記錄提供服務(wù),完了再來取下一條。這樣服務(wù)的時(shí)間就被最有效的利用起來了。

導(dǎo)讀:

J2SE1.4以上版本中發(fā)布了全新的I/O類庫。

NIO庫提供的一些新特性:非阻塞I/O,字符轉(zhuǎn)換,緩沖以及通道。NIO和IO都在rt.jar包中。

一、NIO的簡介

NIO包(java.nio.*)引入了四個(gè)關(guān)鍵的抽象數(shù)據(jù)類型,它們共同解決傳統(tǒng)的I/O類中的一些問題。
1. Buffer:它是包含數(shù)據(jù)且用于讀寫的線形表結(jié)構(gòu)。其中還提供了一個(gè)特殊類用于內(nèi)存映射文件的I/O操作。
2. Charset:它提供Unicode字符串影射到字節(jié)序列以及逆影射的操作。
3. Channels:包含socket,file和pipe三種管道,它實(shí)際上是雙向交流的通道。
4. Selector:它將多元異步I/O操作集中到一個(gè)或多個(gè)線程中(它可以被看成是Unix中select()函數(shù)或Win32中WaitForSingleEvent()函數(shù)的面向?qū)ο蟀姹荆?/p>

二、IO的傳統(tǒng)方式

以網(wǎng)絡(luò)應(yīng)用為例,傳統(tǒng)方式需要監(jiān)聽一個(gè)ServerSocket,接受請求的連接為其提供服務(wù)(服務(wù)通常包括了處理請求并發(fā)送響應(yīng))圖一是服務(wù)器的生命周期圖,其中標(biāo)有粗黑線條的部分表明會發(fā)生I/O阻塞。

圖一

可以分析創(chuàng)建服務(wù)器的每個(gè)具體步驟。首先創(chuàng)建ServerSocket
ServerSocket server=new ServerSocket(10000);
然后接受新的連接請求
Socket newCnotallow=server.accept();
對于accept方法的調(diào)用將造成阻塞,直到ServerSocket接受到一個(gè)連接請求為止。一旦連接請求被接受,服務(wù)器可以讀客戶socket中的請求。

InputStream in = newConnection.getInputStream(); 
InputStreamReader reader = new InputStreamReader(in); 
BufferedReader buffer = new BufferedReader(reader); 
Request request = new Request(); 
while(!request.isComplete()) { 
String line = buffer.readLine(); 
 
request.addLine(line);  }

這樣的操作有兩個(gè)問題,首先BufferedReader類的readLine()方法在其緩沖區(qū)未滿時(shí)會造成線程阻塞,只有一定數(shù)據(jù)填滿了緩沖區(qū)或者客戶關(guān)閉了套接字,方法才會返回。其次,它回產(chǎn)生大量的垃圾,BufferedReader創(chuàng)建了緩沖區(qū)來從客戶套接字讀入數(shù)據(jù),但是同樣創(chuàng)建了一些字符串存儲這些數(shù)據(jù)。雖然BufferedReader內(nèi)部提供了StringBuffer處理這一問題,但是所有的String很快變成了垃圾需要回收。

同樣的問題在發(fā)送響應(yīng)代碼中也存在:

 Response response = request.generateResponse(); 
 OutputStream out = newConnection.getOutputStream(); 
 InputStream in = response.getInputStream(); 
 int ch; 
 while(-1 != (ch = in.read())) { 
 out.write(ch); 
 } 
 newConnection.close();

類似的,讀寫操作被阻塞而且向流中一次寫入一個(gè)字符會造成效率低下,所以應(yīng)該使用緩沖區(qū),但是一旦使用緩沖,流又會產(chǎn)生更多的垃圾。

傳統(tǒng)的解決方法:

通常在Java中處理阻塞I/O要用到線程(大量的線程)。一般是實(shí)現(xiàn)一個(gè)線程池用來處理請求,如圖二

圖二

線程使得服務(wù)器可以處理多個(gè)連接,但是它們也同樣引發(fā)了許多問題。每個(gè)線程擁有自己的??臻g并且占用一些CPU時(shí)間,耗費(fèi)很大,而且很多時(shí)間是浪費(fèi)在阻塞的I/O操作上,沒有有效的利用CPU。

三、NIO的詳細(xì)介紹

1.**** Buffer傳統(tǒng)的I/O不斷的浪費(fèi)對象資源(通常是String)。新I/O通過使用Buffer讀寫數(shù)據(jù)避免了資源浪費(fèi)。Buffer對象是線性的,有序的數(shù)據(jù)集合,它根據(jù)其類別只包含唯一的數(shù)據(jù)類型。
java.nio.Buffer 類描述
java.nio.ByteBuffer 包含字節(jié)類型。 可以從ReadableByteChannel中讀在 WritableByteChannel中寫
java.nio.MappedByteBuffer 包含字節(jié)類型,直接在內(nèi)存某一區(qū)域映射
java.nio.CharBuffer 包含字符類型,不能寫入通道
java.nio.DoubleBuffer 包含double類型,不能寫入通道
java.nio.FloatBuffer 包含float類型
java.nio.IntBuffer 包含int類型
java.nio.LongBuffer 包含long類型
java.nio.ShortBuffer 包含short類型
可以通過調(diào)用allocate(int capacity)方法或者allocateDirect(int capacity)方法分配一個(gè)Buffer。特別的,你可以創(chuàng)建MappedBytesBuffer通過調(diào)用FileChannel.map(int mode,long position,int size)。直接(direct)buffer在內(nèi)存中分配一段連續(xù)的塊并使用本地訪問方法讀寫數(shù)據(jù)。非直接(nondirect)buffer通過使用Java中的數(shù)組訪問代碼讀寫數(shù)據(jù)。有時(shí)候必須使用非直接緩沖例如使用任何的wrap方法(如ByteBuffer.wrap(byte[]))在Java數(shù)組基礎(chǔ)上創(chuàng)建buffer。

2. 字符編碼向ByteBuffer中存放數(shù)據(jù)涉及到兩個(gè)問題:字節(jié)的順序和字符轉(zhuǎn)換。ByteBuffer內(nèi)部通過ByteOrder類處理了字節(jié)順序問題,但是并沒有處理字符轉(zhuǎn)換。事實(shí)上,ByteBuffer沒有提供方法讀寫String。
Java.nio.charset.Charset處理了字符轉(zhuǎn)換問題。它通過構(gòu)造CharsetEncoder和CharsetDecoder將字符序列轉(zhuǎn)換成字節(jié)和逆轉(zhuǎn)換。

3. 通道****(Channel)你可能注意到現(xiàn)有的java.io類中沒有一個(gè)能夠讀寫B(tài)uffer類型,所以NIO中提供了Channel類來讀寫B(tài)uffer。通道可以認(rèn)為是一種連接,可以是到特定設(shè)備,程序或者是網(wǎng)絡(luò)的連接。通道的類等級結(jié)構(gòu)圖如下

圖三

圖中ReadableByteChannel和WritableByteChannel分別用于讀寫。
GatheringByteChannel可以從使用一次將多個(gè)Buffer中的數(shù)據(jù)寫入通道,相反的,ScatteringByteChannel則可以一次將數(shù)據(jù)從通道讀入多個(gè)Buffer中。你還可以設(shè)置通道使其為阻塞或非阻塞I/O操作服務(wù)。
為了使通道能夠同傳統(tǒng)I/O類相容,Channel類提供了靜態(tài)方法創(chuàng)建Stream或Reader

4.**** Selector在過去的阻塞I/O中,我們一般知道什么時(shí)候可以向stream中讀或?qū)?,因?yàn)榉椒ㄕ{(diào)用直到stream準(zhǔn)備好時(shí)返回。但是使用非阻塞通道,我們需要一些方法來知道什么時(shí)候通道準(zhǔn)備好了。在NIO包中,設(shè)計(jì)Selector就是為了這個(gè)目的。SelectableChannel可以注冊特定的事件,而不是在事件發(fā)生時(shí)通知應(yīng)用,通道跟蹤事件。然后,當(dāng)應(yīng)用調(diào)用Selector上的任意一個(gè)selection方法時(shí),它查看注冊了的通道看是否有任何感興趣的事件發(fā)生。

圖四是selector和兩個(gè)已注冊的通道的例子:

圖四

并不是所有的通道都支持所有的操作。SelectionKey類定義了所有可能的操作位,將要用兩次。首先,當(dāng)應(yīng)用調(diào)用SelectableChannel.register(Selector sel,int op)方法注冊通道時(shí),它將所需操作作為第二個(gè)參數(shù)傳遞到方法中。然后,一旦SelectionKey被選中了,SelectionKey的readyOps()方法返回所有通道支持操作的數(shù)位的和。SelectableChannel的validOps方法返回每個(gè)通道允許的操作。注冊通道不支持的操作將引發(fā)IllegalArgumentException異常。下表列出了SelectableChannel子類所支持的操作。

 ServerSocketChannel OP_ACCEPT 
 SocketChannel OP_CONNECT, OP_READ, OP_WRITE 
 DatagramChannel OP_READ, OP_WRITE 
 Pipe.SourceChannel OP_READ 
 Pipe.SinkChannel OP_WRITE

四. 舉例說明

1. 簡單網(wǎng)頁內(nèi)容下載這個(gè)例子非常簡單,類SocketChannelReader使用SocketChannel來下載特定網(wǎng)頁的HTML內(nèi)容。
package examples.nio;

package com.yineng.mycat; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.net.InetSocketAddress; import java.io.IOException; /** * @author kzfy
* @data 2015/12/21 */
public class SocketChannelReader{ private Charset charset=Charset.forName("UTF-8");//創(chuàng)建UTF-8字符集

private SocketChannel channel; public void getHTMLContent(){ try{
connect();
sendRequest();
readResponse();
}catch(IOException e){
System.err.println(e.toString());
}finally{ if(channel!=null){ try{
channel.close();
}catch(IOException e){}
}
}
} private void connect()throws IOException{//連接到CSDN InetSocketAddress socketAddress= new InetSocketAddress("http://www.csdn.net",80);
channel=SocketChannel.open(socketAddress); //使用工廠方法open創(chuàng)建一個(gè)channel并將它連接到指定地址上 //相當(dāng)與SocketChannel.open().connect(socketAddress);調(diào)用 } private void sendRequest()throws IOException{
channel.write(charset.encode("GET /document\r\n\r\n"));//發(fā)送GET請求到CSDN的文檔中心 //使用channel.write方法,它需要CharByte類型的參數(shù),使用 //Charset.encode(String)方法轉(zhuǎn)換字符串。
} private void readResponse()throws IOException{//讀取應(yīng)答
ByteBuffer buffer=ByteBuffer.allocate(1024);//創(chuàng)建1024字節(jié)的緩沖
while(channel.read(buffer)!=-1){
buffer.flip();//flip方法在讀緩沖區(qū)字節(jié)操作之前調(diào)用。
System.out.println(charset.decode(buffer)); //使用Charset.decode方法將字節(jié)轉(zhuǎn)換為字符串
buffer.clear();//清空緩沖
}
} public static void main(String [] args){ new SocketChannelReader().getHTMLContent();
}
}

到此這篇關(guān)于Java NIO與IO的區(qū)別以及比較的文章就介紹到這了,更多相關(guān)Java NIO與IO 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springMVC+jersey實(shí)現(xiàn)跨服務(wù)器文件上傳

    springMVC+jersey實(shí)現(xiàn)跨服務(wù)器文件上傳

    這篇文章主要介紹了springMVC+jersey實(shí)現(xiàn)跨服務(wù)器文件上傳,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • SpringBoot實(shí)現(xiàn)excel生成并且通過郵件發(fā)送的步驟詳解

    SpringBoot實(shí)現(xiàn)excel生成并且通過郵件發(fā)送的步驟詳解

    實(shí)際開發(fā)中,特別是在B端產(chǎn)品的開發(fā)中,我們經(jīng)常會遇到導(dǎo)出excel的功能,更進(jìn)階一點(diǎn)的需要我們定期生成統(tǒng)計(jì)報(bào)表,然后通過郵箱發(fā)送給指定的人員,?今天要帶大家來實(shí)現(xiàn)的就是excel生成并通過郵件發(fā)送,需要的朋友可以參考下
    2023-10-10
  • 關(guān)于Integer.parseInt()方法的使用

    關(guān)于Integer.parseInt()方法的使用

    這篇文章主要介紹了關(guān)于Integer.parseInt()方法的使用,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Springboot實(shí)現(xiàn)緩存預(yù)熱的方法

    Springboot實(shí)現(xiàn)緩存預(yù)熱的方法

    在系統(tǒng)啟動之前通過預(yù)先將常用數(shù)據(jù)加載到緩存中,以提高緩存命中率和系統(tǒng)性能的過程,緩存預(yù)熱的目的是盡可能地避免緩存擊穿和緩存雪崩,這篇文章主要介紹了Springboot實(shí)現(xiàn)緩存預(yù)熱,需要的朋友可以參考下
    2024-03-03
  • GsonFormat快速生成JSon實(shí)體類的實(shí)現(xiàn)

    GsonFormat快速生成JSon實(shí)體類的實(shí)現(xiàn)

    GsonFormat主要用于使用Gson庫將JSONObject格式的String?解析成實(shí)體,本文主要介紹了GsonFormat快速生成JSon實(shí)體類的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-05-05
  • VsCode搭建Spring Boot項(xiàng)目并進(jìn)行創(chuàng)建、運(yùn)行、調(diào)試

    VsCode搭建Spring Boot項(xiàng)目并進(jìn)行創(chuàng)建、運(yùn)行、調(diào)試

    這篇文章主要介紹了VsCode搭建Spring Boot項(xiàng)目并進(jìn)行創(chuàng)建、運(yùn)行、調(diào)試 ,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Servlet實(shí)現(xiàn)文件的上傳與下載

    Servlet實(shí)現(xiàn)文件的上傳與下載

    這篇文章主要為大家詳細(xì)介紹了Servlet實(shí)現(xiàn)文件的上傳與下載,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • java之swing單選框用法實(shí)例分析

    java之swing單選框用法實(shí)例分析

    這篇文章主要介紹了java之swing單選框用法,以實(shí)例形式分析了swing圖形界面單選框的實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-09-09
  • Spring的@RequestParam對象綁定方式

    Spring的@RequestParam對象綁定方式

    這篇文章主要介紹了Spring的@RequestParam對象綁定方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • MyBatis中example.createCriteria()方法的具體使用

    MyBatis中example.createCriteria()方法的具體使用

    本文詳細(xì)介紹了MyBatis的Example工具的使用方法,包括鏈?zhǔn)秸{(diào)用指定字段、設(shè)置查詢條件、支持多種查詢方式等,還介紹了mapper的crud方法、and/or方法的使用,以及如何進(jìn)行多條件和多重條件查詢,感興趣的可以了解一下
    2024-10-10

最新評論