中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

網(wǎng)站建設(shè)環(huán)境分析百度推廣一般多少錢

網(wǎng)站建設(shè)環(huán)境分析,百度推廣一般多少錢,網(wǎng)站創(chuàng)建人是,有域名和主機(jī)怎么做網(wǎng)站第11講 | Java提供了哪些IO方式? NIO如何實(shí)現(xiàn)多路復(fù)用? IO 一直是軟件開發(fā)中的核心部分之一,伴隨著海量數(shù)據(jù)增長(zhǎng)和分布式系統(tǒng)的發(fā)展,IO 擴(kuò)展能力愈發(fā)重要。幸運(yùn)的是,Java 平臺(tái) IO 機(jī)制經(jīng)過不斷完善,雖然在某…

第11講 | Java提供了哪些IO方式? NIO如何實(shí)現(xiàn)多路復(fù)用?

在這里插入圖片描述

IO 一直是軟件開發(fā)中的核心部分之一,伴隨著海量數(shù)據(jù)增長(zhǎng)和分布式系統(tǒng)的發(fā)展,IO 擴(kuò)展能力愈發(fā)重要。幸運(yùn)的是,Java 平臺(tái) IO 機(jī)制經(jīng)過不斷完善,雖然在某些方面仍有不足,但已經(jīng)在實(shí)踐中證明了其構(gòu)建高擴(kuò)展性應(yīng)用的能力。

今天我要問你的問題是,Java 提供了哪些 IO 方式? NIO 如何實(shí)現(xiàn)多路復(fù)用?

典型回答

Java IO 方式有很多種,基于不同的 IO 抽象模型和交互方式,可以進(jìn)行簡(jiǎn)單區(qū)分。

第一,傳統(tǒng)的 java.io 包,它基于流模型實(shí)現(xiàn),提供了我們最熟知的一些 IO 功能,比如 File 抽象、輸入輸出流等。交互方式是同步、阻塞的方式,也就是說,在讀取輸入流或者寫入輸出流時(shí),在讀、寫動(dòng)作完成之前,線程會(huì)一直阻塞在那里,它們之間的調(diào)用是可靠的線性順序。

java.io 包的好處是代碼比較簡(jiǎn)單、直觀,缺點(diǎn)則是 IO 效率和擴(kuò)展性存在局限性,容易成為應(yīng)用性能的瓶頸。

很多時(shí)候,人們也把 java.net 下面提供的部分網(wǎng)絡(luò) API,比如 Socket、ServerSocket、HttpURLConnection 也歸類到同步阻塞 IO 類庫(kù),因?yàn)榫W(wǎng)絡(luò)通信同樣是 IO 行為。

第二,在 Java 1.4 中引入了 NIO 框架(java.nio 包),提供了 Channel、Selector、Buffer 等新的抽象,可以構(gòu)建多路復(fù)用的、同步非阻塞 IO 程序,同時(shí)提供了更接近操作系統(tǒng)底層的高性能數(shù)據(jù)操作方式。

第三,在 Java 7 中,NIO 有了進(jìn)一步的改進(jìn),也就是 NIO 2,引入了異步非阻塞 IO 方式,也有很多人叫它 AIO(Asynchronous IO)。異步 IO 操作基于事件和回調(diào)機(jī)制,可以簡(jiǎn)單理解為,應(yīng)用操作直接返回,而不會(huì)阻塞在那里,當(dāng)后臺(tái)處理完成,操作系統(tǒng)會(huì)通知相應(yīng)線程進(jìn)行后續(xù)工作。

考點(diǎn)分析

我上面列出的回答是基于一種常見分類方式,即所謂的 BIO、NIO、NIO 2(AIO)。

在實(shí)際面試中,從傳統(tǒng) IO 到 NIO、NIO 2,其中有很多地方可以擴(kuò)展開來,考察點(diǎn)涉及方方面面,比如:

基礎(chǔ) API 功能與設(shè)計(jì), InputStream/OutputStream 和 Reader/Writer 的關(guān)系和區(qū)別。

NIO、NIO 2 的基本組成。

給定場(chǎng)景,分別用不同模型實(shí)現(xiàn),分析 BIO、NIO 等模式的設(shè)計(jì)和實(shí)現(xiàn)原理。

NIO 提供的高性能數(shù)據(jù)操作方式是基于什么原理,如何使用?

或者,從開發(fā)者的角度來看,你覺得 NIO 自身實(shí)現(xiàn)存在哪些問題?有什么改進(jìn)的想法嗎?

IO 的內(nèi)容比較多,專欄一講很難能夠說清楚。IO 不僅僅是多路復(fù)用,NIO 2 也不僅僅是異步 IO,尤其是數(shù)據(jù)操作部分,會(huì)在專欄下一講詳細(xì)分析。

知識(shí)擴(kuò)展

首先,需要澄清一些基本概念:

區(qū)分同步或異步(synchronous/asynchronous)。簡(jiǎn)單來說,同步是一種可靠的有序運(yùn)行機(jī)制,當(dāng)我們進(jìn)行同步操作時(shí),后續(xù)的任務(wù)是等待當(dāng)前調(diào)用返回,才會(huì)進(jìn)行下一步;而異步則相反,其他任務(wù)不需要等待當(dāng)前調(diào)用返回,通常依靠事件、回調(diào)等機(jī)制來實(shí)現(xiàn)任務(wù)間次序關(guān)系。

區(qū)分阻塞與非阻塞(blocking/non-blocking)。在進(jìn)行阻塞操作時(shí),當(dāng)前線程會(huì)處于阻塞狀態(tài),無(wú)法從事其他任務(wù),只有當(dāng)條件就緒才能繼續(xù),比如 ServerSocket 新連接建立完畢,或數(shù)據(jù)讀取、寫入操作完成;而非阻塞則是不管 IO 操作是否結(jié)束,直接返回,相應(yīng)操作在后臺(tái)繼續(xù)處理。

不能一概而論認(rèn)為同步或阻塞就是低效,具體還要看應(yīng)用和系統(tǒng)特征。

對(duì)于 java.io,我們都非常熟悉,我這里就從總體上進(jìn)行一下總結(jié),如果需要學(xué)習(xí)更加具體的操作,你可以通過教程等途徑完成。總體上,我認(rèn)為你至少需要理解一下內(nèi)容。

IO 不僅僅是對(duì)文件的操作,網(wǎng)絡(luò)編程中,比如 Socket 通信,都是典型的 IO 操作目標(biāo)。

輸入流、輸出流(InputStream/OutputStream)是用于讀取或?qū)懭胱止?jié)的,例如操作圖片文件。

而 Reader/Writer 則是用于操作字符,增加了字符編解碼等功能,適用于類似從文件中讀取或者寫入文本信息。本質(zhì)上計(jì)算機(jī)操作的都是字節(jié),不管是網(wǎng)絡(luò)通信還是文件讀取,Reader/Writer 相當(dāng)于構(gòu)建了應(yīng)用邏輯和原始數(shù)據(jù)之間的橋梁。

BufferedOutputStream 等帶緩沖區(qū)的實(shí)現(xiàn),可以避免頻繁的磁盤讀寫,進(jìn)而提高 IO 處理效率。這種設(shè)計(jì)利用了緩沖區(qū),將批量數(shù)據(jù)進(jìn)行一次操作,但在使用中千萬(wàn)別忘了 flush。

參考下面這張類圖,很多 IO 工具類都實(shí)現(xiàn)了 Closeable 接口,因?yàn)樾枰M(jìn)行資源的釋放。比如,打開 FileInputStream,它就會(huì)獲取相應(yīng)的文件描述符(FileDescriptor),需要利用 try-with-resources、 try-finally 等機(jī)制保證 FileInputStream 被明確關(guān)閉,進(jìn)而相應(yīng)文件描述符也會(huì)失效,否則將導(dǎo)致資源無(wú)法被釋放。利用專欄前面的內(nèi)容提到的 Cleaner 或 finalize 機(jī)制作為資源釋放的最后把關(guān),也是必要的。

下面是我整理的一個(gè)簡(jiǎn)化版的類圖,闡述了日常開發(fā)應(yīng)用較多的類型和結(jié)構(gòu)關(guān)系。

在這里插入圖片描述

  1. Java NIO 概覽

    首先,熟悉一下 NIO 的主要組成部分:

    Buffer,高效的數(shù)據(jù)容器,除了布爾類型,所有原始數(shù)據(jù)類型都有相應(yīng)的 Buffer 實(shí)現(xiàn)。

    Channel,類似在 Linux 之類操作系統(tǒng)上看到的文件描述符,是 NIO 中被用來支持批量式 IO 操作的一種抽象。

    File 或者 Socket,通常被認(rèn)為是比較高層次的抽象,而 Channel 則是更加操作系統(tǒng)底層的一種抽象,這也使得 NIO 得以充分利用現(xiàn)代操作系統(tǒng)底層機(jī)制,獲得特定場(chǎng)景的性能優(yōu)化,例如,DMA(Direct Memory Access)等。不同層次的抽象是相互關(guān)聯(lián)的,我們可以通過 Socket 獲取 Channel,反之亦然。

    Selector,是 NIO 實(shí)現(xiàn)多路復(fù)用的基礎(chǔ),它提供了一種高效的機(jī)制,可以檢測(cè)到注冊(cè)在 Selector 上的多個(gè) Channel 中,是否有 Channel 處于就緒狀態(tài),進(jìn)而實(shí)現(xiàn)了單線程對(duì)多 Channel 的高效管理。Selector 同樣是基于底層操作系統(tǒng)機(jī)制,不同模式、不同版本都存在區(qū)別,例如,在最新的代碼庫(kù)里,相關(guān)實(shí)現(xiàn)如下:

Charset,提供 Unicode 字符串定義,NIO 也提供了相應(yīng)的編解碼器等,例如,通過下面的方式進(jìn)行字符串到 ByteBuffer 的轉(zhuǎn)換:

Charset.defaultCharset().encode("Hello world!"));
  1. NIO 能解決什么問題?

    下面我通過一個(gè)典型場(chǎng)景,來分析為什么需要 NIO,為什么需要多路復(fù)用。設(shè)想,我們需要實(shí)現(xiàn)一個(gè)服務(wù)器應(yīng)用,只簡(jiǎn)單要求能夠同時(shí)服務(wù)多個(gè)客戶端請(qǐng)求即可。

    使用 java.io 和 java.net 中的同步、阻塞式 API,可以簡(jiǎn)單實(shí)現(xiàn)。

    
    public class DemoServer extends Thread {private ServerSocket serverSocket;public int getPort() {return  serverSocket.getLocalPort();}public void run() {try {serverSocket = new ServerSocket(0);while (true) {Socket socket = serverSocket.accept();RequestHandler requestHandler = new RequestHandler(socket);requestHandler.start();}} catch (IOException e) {e.printStackTrace();} finally {if (serverSocket != null) {try {serverSocket.close();} catch (IOException e) {e.printStackTrace();};}}}public static void main(String[] args) throws IOException {DemoServer server = new DemoServer();server.start();try (Socket client = new Socket(InetAddress.getLocalHost(), server.getPort())) {BufferedReader bufferedReader = new BufferedReader(new                   InputStreamReader(client.getInputStream()));bufferedReader.lines().forEach(s -> System.out.println(s));}}}
    // 簡(jiǎn)化實(shí)現(xiàn),不做讀取,直接發(fā)送字符串
    class RequestHandler extends Thread {private Socket socket;RequestHandler(Socket socket) {this.socket = socket;}@Overridepublic void run() {try (PrintWriter out = new PrintWriter(socket.getOutputStream());) {out.println("Hello world!");out.flush();} catch (Exception e) {e.printStackTrace();}}}

    其實(shí)現(xiàn)要點(diǎn)是:

    服務(wù)器端啟動(dòng) ServerSocket,端口 0 表示自動(dòng)綁定一個(gè)空閑端口。

    調(diào)用 accept 方法,阻塞等待客戶端連接。

    利用 Socket 模擬了一個(gè)簡(jiǎn)單的客戶端,只進(jìn)行連接、讀取、打印。

    當(dāng)連接建立后,啟動(dòng)一個(gè)單獨(dú)線程負(fù)責(zé)回復(fù)客戶端請(qǐng)求。

    這樣,一個(gè)簡(jiǎn)單的 Socket 服務(wù)器就被實(shí)現(xiàn)出來了。

思考一下,這個(gè)解決方案在擴(kuò)展性方面,可能存在什么潛在問題呢?

大家知道 Java 語(yǔ)言目前的線程實(shí)現(xiàn)是比較重量級(jí)的,啟動(dòng)或者銷毀一個(gè)線程是有明顯開銷的,每個(gè)線程都有單獨(dú)的線程棧等結(jié)構(gòu),需要占用非常明顯的內(nèi)存,所以,每一個(gè) Client 啟動(dòng)一個(gè)線程似乎都有些浪費(fèi)。

那么,稍微修正一下這個(gè)問題,我們引入線程池機(jī)制來避免浪費(fèi)。


serverSocket = new ServerSocket(0);
executor = Executors.newFixedThreadPool(8);while (true) {Socket socket = serverSocket.accept();RequestHandler requestHandler = new RequestHandler(socket);executor.execute(requestHandler);
}

這樣做似乎好了很多,通過一個(gè)固定大小的線程池,來負(fù)責(zé)管理工作線程,避免頻繁創(chuàng)建、銷毀線程的開銷,這是我們構(gòu)建并發(fā)服務(wù)的典型方式。這種工作方式,可以參考下圖來理解。

在這里插入圖片描述

如果連接數(shù)并不是非常多,只有最多幾百個(gè)連接的普通應(yīng)用,這種模式往往可以工作的很好。但是,如果連接數(shù)量急劇上升,這種實(shí)現(xiàn)方式就無(wú)法很好地工作了,因?yàn)榫€程上下文切換開銷會(huì)在高并發(fā)時(shí)變得很明顯,這是同步阻塞方式的低擴(kuò)展性劣勢(shì)。

NIO 引入的多路復(fù)用機(jī)制,提供了另外一種思路,請(qǐng)參考我下面提供的新的版本。


public class NIOServer extends Thread {public void run() {try (Selector selector = Selector.open();ServerSocketChannel serverSocket = ServerSocketChannel.open();) {// 創(chuàng)建Selector和ChannelserverSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 8888));serverSocket.configureBlocking(false);// 注冊(cè)到Selector,并說明關(guān)注點(diǎn)serverSocket.register(selector, SelectionKey.OP_ACCEPT);while (true) {selector.select();// 阻塞等待就緒的Channel,這是關(guān)鍵點(diǎn)之一Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> iter = selectedKeys.iterator();while (iter.hasNext()) {SelectionKey key = iter.next();// 生產(chǎn)系統(tǒng)中一般會(huì)額外進(jìn)行就緒狀態(tài)檢查sayHelloWorld((ServerSocketChannel) key.channel());iter.remove();}}} catch (IOException e) {e.printStackTrace();}}private void sayHelloWorld(ServerSocketChannel server) throws IOException {try (SocketChannel client = server.accept();) {          client.write(Charset.defaultCharset().encode("Hello world!"));}}// 省略了與前面類似的main
}

這個(gè)非常精簡(jiǎn)的樣例掀開了 NIO 多路復(fù)用的面紗,我們可以分析下主要步驟和元素:

首先,通過 Selector.open() 創(chuàng)建一個(gè) Selector,作為類似調(diào)度員的角色。

然后,創(chuàng)建一個(gè) ServerSocketChannel,并且向 Selector 注冊(cè),通過指定 SelectionKey.OP_ACCEPT,告訴調(diào)度員,它關(guān)注的是新的連接請(qǐng)求。注意,為什么我們要明確配置非阻塞模式呢?這是因?yàn)樽枞J较?#xff0c;注冊(cè)操作是不允許的,會(huì)拋出 IllegalBlockingModeException 異常。

Selector 阻塞在 select 操作,當(dāng)有 Channel 發(fā)生接入請(qǐng)求,就會(huì)被喚醒。

在 sayHelloWorld 方法中,通過 SocketChannel 和 Buffer 進(jìn)行數(shù)據(jù)操作,在本例中是發(fā)送了一段字符串。

可以看到,在前面兩個(gè)樣例中,IO 都是同步阻塞模式,所以需要多線程以實(shí)現(xiàn)多任務(wù)處理。而 NIO 則是利用了單線程輪詢事件的機(jī)制,通過高效地定位就緒的 Channel,來決定做什么,僅僅 select 階段是阻塞的,可以有效避免大量客戶端連接時(shí),頻繁線程切換帶來的問題,應(yīng)用的擴(kuò)展能力有了非常大的提高。下面這張圖對(duì)這種實(shí)現(xiàn)思路進(jìn)行了形象地說明。

在 Java 7 引入的 NIO 2 中,又增添了一種額外的異步 IO 模式,利用事件和回調(diào),處理 Accept、Read 等操作。 AIO 實(shí)現(xiàn)看起來是類似這樣子:


AsynchronousServerSocketChannel serverSock =        AsynchronousServerSocketChannel.open().bind(sockAddr);
serverSock.accept(serverSock, new CompletionHandler<>() { //為異步操作指定CompletionHandler回調(diào)函數(shù)@Overridepublic void completed(AsynchronousSocketChannel sockChannel, AsynchronousServerSocketChannel serverSock) {serverSock.accept(serverSock, this);// 另外一個(gè) write(sock,CompletionHandler{})sayHelloWorld(sockChannel, Charset.defaultCharset().encode("Hello World!"));}// 省略其他路徑處理方法...
});

鑒于其編程要素(如 Future、CompletionHandler 等),我們還沒有進(jìn)行準(zhǔn)備工作,為避免理解困難,我會(huì)在專欄后面相關(guān)概念補(bǔ)充后的再進(jìn)行介紹,尤其是 Reactor、Proactor 模式等方面將在 Netty 主題一起分析,這里我先進(jìn)行概念性的對(duì)比:

基本抽象很相似,AsynchronousServerSocketChannel 對(duì)應(yīng)于上面例子中的 ServerSocketChannel;AsynchronousSocketChannel 則對(duì)應(yīng) SocketChannel。

業(yè)務(wù)邏輯的關(guān)鍵在于,通過指定 CompletionHandler 回調(diào)接口,在 accept/read/write 等關(guān)鍵節(jié)點(diǎn),通過事件機(jī)制調(diào)用,這是非常不同的一種編程思路。

今天我初步對(duì) Java 提供的 IO 機(jī)制進(jìn)行了介紹,概要地分析了傳統(tǒng)同步 IO 和 NIO 的主要組成,并根據(jù)典型場(chǎng)景,通過不同的 IO 模式進(jìn)行了實(shí)現(xiàn)與拆解。專欄下一講,我還將繼續(xù)分析 Java IO 的主題。

一課一練

關(guān)于今天我們討論的題目你做到心中有數(shù)了嗎?留一道思考題給你,NIO 多路復(fù)用的局限性是什么呢?你遇到過相關(guān)的問題嗎?

請(qǐng)你在留言區(qū)寫寫你對(duì)這個(gè)問題的思考,我會(huì)選出經(jīng)過認(rèn)真思考的留言,送給你一份學(xué)習(xí)鼓勵(lì)金,歡迎你與我一起討論。

業(yè)務(wù)邏輯的關(guān)鍵在于,通過指定 CompletionHandler 回調(diào)接口,在 accept/read/write 等關(guān)鍵節(jié)點(diǎn),通過事件機(jī)制調(diào)用,這是非常不同的一種編程思路。

今天我初步對(duì) Java 提供的 IO 機(jī)制進(jìn)行了介紹,概要地分析了傳統(tǒng)同步 IO 和 NIO 的主要組成,并根據(jù)典型場(chǎng)景,通過不同的 IO 模式進(jìn)行了實(shí)現(xiàn)與拆解。專欄下一講,我還將繼續(xù)分析 Java IO 的主題。

一課一練

關(guān)于今天我們討論的題目你做到心中有數(shù)了嗎?留一道思考題給你,NIO 多路復(fù)用的局限性是什么呢?你遇到過相關(guān)的問題嗎?

請(qǐng)你在留言區(qū)寫寫你對(duì)這個(gè)問題的思考,我會(huì)選出經(jīng)過認(rèn)真思考的留言,送給你一份學(xué)習(xí)鼓勵(lì)金,歡迎你與我一起討論。

你的朋友是不是也在準(zhǔn)備面試呢?你可以“請(qǐng)朋友讀”,把今天的題目分享給好友,或許你能幫到他。

http://www.risenshineclean.com/news/43397.html

相關(guān)文章:

  • 曲阜做網(wǎng)站最佳磁力搜索天堂
  • 2014做網(wǎng)站百度移動(dòng)端點(diǎn)贊排名軟件
  • 外貿(mào)軟件定制域名查詢seo
  • 做網(wǎng)站排名的公司有哪些最好的營(yíng)銷策劃公司
  • 聾啞工作設(shè)計(jì)做網(wǎng)站免費(fèi)長(zhǎng)尾詞挖掘工具
  • 怎樣做代刷網(wǎng)站百度廣告投放平臺(tái)叫什么
  • 電子類網(wǎng)站模板昆明百度推廣開戶費(fèi)用
  • 廣州做網(wǎng)站多百度小說排行榜前十名
  • wordpress的列表汕頭seo公司
  • 西安定制網(wǎng)站建設(shè)中國(guó)知名網(wǎng)站排行榜
  • 四川疫情最新消息2019網(wǎng)站推廣優(yōu)化技巧
  • 如何做網(wǎng)站大管家如何優(yōu)化推廣網(wǎng)站
  • 陜西西安網(wǎng)站建設(shè)公司排名重慶seo排名技術(shù)
  • 無(wú)錫做網(wǎng)站哪里好成都全網(wǎng)營(yíng)銷推廣
  • 織夢(mèng)做電子商務(wù)網(wǎng)站小紅書seo排名帝搜軟件
  • 什么是網(wǎng)站建設(shè)和維護(hù)廈門seo小謝
  • 成功營(yíng)銷案例免費(fèi)seo營(yíng)銷優(yōu)化軟件下載
  • 做外貿(mào)網(wǎng)站要注意什么查企業(yè)信息查詢平臺(tái)
  • 騰訊云服務(wù)器用什么做網(wǎng)站企業(yè)培訓(xùn)課程視頻
  • 個(gè)人養(yǎng)老金查詢山東seo多少錢
  • 廣州網(wǎng)站制作公司優(yōu)化獨(dú)立站平臺(tái)選哪個(gè)好
  • 今天西安新消息抖音seo運(yùn)營(yíng)模式
  • wordpress模板建站教程視頻微信騰訊會(huì)議
  • 網(wǎng)站建設(shè)中404什么意思宣傳產(chǎn)品的方式
  • b站必看的紀(jì)錄片廣告平臺(tái)
  • 動(dòng)態(tài)商務(wù)網(wǎng)站開發(fā)與管理電商培訓(xùn)視頻教程
  • 教做年糕博客網(wǎng)站同城推廣
  • wordpress 極簡(jiǎn)主題紹興網(wǎng)站快速排名優(yōu)化
  • 公司網(wǎng)站備案需要什么資料友情鏈接交換的作用在于
  • 蕪湖市建設(shè)辦網(wǎng)站谷歌關(guān)鍵詞搜索量數(shù)據(jù)查詢