摘要:也支持鎖定部分內(nèi)容,使用即可,其中為時(shí),表明該鎖是一個(gè)共享鎖,可以允許多個(gè)縣城讀取文件,但阻止其他進(jìn)程獲得該文件的排他鎖。當(dāng)為時(shí),表明是一個(gè)排他鎖,它將鎖住對(duì)該文件的讀寫(xiě)。默認(rèn)獲取的是排他鎖。
Java的NIO
BufferedReader有一個(gè)特征,就是讀取輸入流中的數(shù)據(jù)時(shí),如果沒(méi)有讀到有效數(shù)據(jù),程序?qū)⒃诖颂幾枞摼€程的執(zhí)行(使用InputStream的read方法從流中讀取數(shù)據(jù)時(shí),也有這樣的特性),java.io下面的輸入輸出流都是阻塞式的。不僅如此,傳統(tǒng)的輸入輸出流都是通過(guò)字節(jié)的移動(dòng)來(lái)處理的,及時(shí)我們不直接去處理字節(jié)流,單底層的實(shí)現(xiàn)還是依賴于字節(jié)處理,也就是說(shuō),面向流的輸入輸出系統(tǒng)一次只能處理一個(gè)字節(jié),因此面向流的輸入輸出系統(tǒng)通常效率都不高。
為了解決上面的問(wèn)題,NIO就出現(xiàn)了。NIO采用內(nèi)存映射文件來(lái)處理輸入輸出,NIO將文件或文件的一段區(qū)域映射到內(nèi)存中,這樣就可以像訪問(wèn)內(nèi)存一樣來(lái)訪問(wèn)文件了。(這種方式模擬了操作系統(tǒng)上虛擬內(nèi)存的概念),通過(guò)這種方式進(jìn)行輸入輸出要快得多。
Channel(通道)和Buffer(緩沖)是NIO中兩個(gè)核心對(duì)象。Channel是對(duì)傳統(tǒng)的輸入輸出系統(tǒng)的模擬,在NIO系統(tǒng)中所有的數(shù)據(jù)都需要通過(guò)通道傳輸,Channel與傳統(tǒng)的InputStream、OutputStream最大的區(qū)別就是提供了一個(gè)map()方法,通過(guò)它可以直接將“一塊數(shù)據(jù)”映射到內(nèi)存中。如果說(shuō)傳統(tǒng)IO是面向流的處理,那么NIO是面向塊的處理。
Buffer可以被理解為一個(gè)容器,它的本質(zhì)是一個(gè)數(shù)組,發(fā)送到Channel中所有的對(duì)象都必須首先放到Buffer中,從而Channel中讀取的數(shù)據(jù)也必須先放到Buffer中。Buffer既可以一次次從Channel取數(shù)據(jù),也可以使用Channel直接將文件的某塊數(shù)據(jù)映射成Buffer。
除了Channel和Buffer之外,NIO還提供了用于將Unicode字符串映射成字節(jié)序列以及逆映射操作的Charset類,也提供了用于支持非阻塞式輸入輸出的Selector類。
Buffer介紹在Buffer中有三個(gè)重要的概念:
容量(capacity):表示Buffer的大小,創(chuàng)建后不能呢過(guò)改變;
界限(limit):第一個(gè)不能被讀寫(xiě)的緩沖區(qū)的位置,也就是后面的數(shù)據(jù)不能被讀寫(xiě);
位置(position):用于指明下一個(gè)可以被讀寫(xiě)的緩沖區(qū)位置索引。當(dāng)從Channel讀取數(shù)據(jù)的時(shí)候,position的值就等于讀到了多少數(shù)據(jù)。
Buffer的主要作用就是裝入數(shù)據(jù),然后輸出數(shù)據(jù)。當(dāng)裝入數(shù)據(jù)結(jié)束時(shí),調(diào)用flip()方法,該方法將limit設(shè)為position所在位置,將position的值設(shè)為0,為輸出數(shù)據(jù)做好準(zhǔn)備。當(dāng)輸出數(shù)據(jù)結(jié)束后,調(diào)用clear()方法,將position的值設(shè)為0,limit設(shè)為capacity,為下一次的裝入數(shù)據(jù)做準(zhǔn)備。
常用的Buffer是CharBuffer和ByteBuffer。
使用put()和get()方法進(jìn)行數(shù)據(jù)的放入和讀取,分為相對(duì)和絕對(duì)兩種:
相對(duì):從Buffer當(dāng)前position位置開(kāi)始讀取或者寫(xiě)入數(shù)據(jù),然后將position的值按處理元素的個(gè)數(shù)增加;
絕對(duì):直接根據(jù)索引向Buffer中讀取和寫(xiě)入數(shù)據(jù),使用絕對(duì)方式訪問(wèn)Buffer里的數(shù)據(jù)時(shí),不會(huì)影響position的值。
代碼示例
package com.wangjun.othersOfJava; import java.nio.CharBuffer; public class NIOBufferTest { public static void main(String[] args) { //創(chuàng)建CharBuffer CharBuffer cb = CharBuffer.allocate(8); System.out.println("capacity:" + cb.capacity()); System.out.println("limit:" + cb.limit()); System.out.println("position:" + cb.position()); //放入元素 cb.put("a"); cb.put("b"); cb.put("c"); System.out.println("加入三個(gè)元素后,position:" + cb.position()); cb.flip(); System.out.println("執(zhí)行flip()后,limit:" + cb.limit()); System.out.println("執(zhí)行flip()后,position:" + cb.position()); System.out.println("取出第一個(gè)元素: " + cb.get()); System.out.println("取出第一個(gè)元素后,position:" + cb.position()); //調(diào)用clear方法 cb.clear(); System.out.println("執(zhí)行clear()后,limit:" + cb.limit()); System.out.println("執(zhí)行clear()后,position:" + cb.position()); System.out.println("執(zhí)行clear()后,數(shù)據(jù)沒(méi)有清空,第三個(gè)值是:" + cb.get(2)); System.out.println("執(zhí)行絕對(duì)讀取后,position:" + cb.position()); } }
通過(guò)allocate方法創(chuàng)建的是普通Buffer,還可以通過(guò)allocateDirect方法來(lái)創(chuàng)建直接Buffer,雖然創(chuàng)建成本比較高,但是讀寫(xiě)快。因此適用于長(zhǎng)期生存的Buffer,使用方法和普通Buffer類似。注意,只有ByteBuffer提供了此方法,其他類型的想用,可以將該Buffer轉(zhuǎn)成其他類型的Buffer。
Channel(通道)介紹Channel類似傳統(tǒng)的流對(duì)象,主要區(qū)別如下:
Channel可以直接將指定文件的部分或全部直接映射成Buffer。
程序不能直接訪問(wèn)Channel中的數(shù)據(jù),只能通過(guò)Buffer交互。
所有的Channel都不應(yīng)該通過(guò)構(gòu)造器來(lái)創(chuàng)建,而是通過(guò)傳統(tǒng)的InputStream、OutputStream的getChannel()方法來(lái)返回對(duì)應(yīng)的Channel,不同的節(jié)點(diǎn)流獲取的Channel不一樣,比如FileInputStream返回的是FileChannel。
Channel常用的方法有三類:map()、read()、write()。map方法將Channel對(duì)應(yīng)的部分或全部數(shù)據(jù)映射成ByteBuffer;read和write方法都有一系列的重載形式,這些方法用于從Buffer中讀取/寫(xiě)入數(shù)據(jù)。
代碼示例
package com.wangjun.othersOfJava; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.CharBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; /* * 將FileChannel的全部數(shù)據(jù)映射成ByteBuffer */ public class NIOChannelTest { public static void main(String[] args) throws Exception { File f = new File("NIOChannelTest.md"); //java7新特性try括號(hào)內(nèi)的資源會(huì)在try語(yǔ)句結(jié)束后自動(dòng)釋放,前提是這些可關(guān)閉的資源必須實(shí)現(xiàn) java.lang.AutoCloseable 接口。 try( FileChannel inChannel = new FileInputStream(f).getChannel(); FileChannel outChannel = new FileOutputStream("a.md").getChannel(); ){ //將FileChannel的全部數(shù)據(jù)映射成ByteBuffer //map方法的三個(gè)參數(shù):1映射模式;2,3控制將哪些數(shù)據(jù)映射成ByteBuffer MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length()); //直接將buffer的數(shù)據(jù)全部輸出,完成文件的復(fù)制: NIOChannelTest.md -> a.md outChannel.write(buffer); //以下為了輸出文件字符串內(nèi)容 //使用GBK字符集來(lái)創(chuàng)建解碼器 Charset charset = Charset.forName("GBK"); //復(fù)原limit和position的位置 buffer.clear(); //創(chuàng)建解碼器 CharsetDecoder decoder = charset.newDecoder(); //使用解碼器將ByteBuffer轉(zhuǎn)成CharBuffer CharBuffer charBuffer = decoder.decode(buffer); System.out.println(charBuffer); } } }
除了上面的一次性取數(shù)據(jù),也可以分多次取數(shù)據(jù)
//如果Channel對(duì)應(yīng)的文件過(guò)大,使用map方法一次性將所有文件內(nèi)容映射到內(nèi)存中可能會(huì)因此性能下降 //這時(shí)候我們可以適應(yīng)Channel和Buffer進(jìn)行多次重復(fù)取值 public static void getDataByArray() throws Exception { try( //創(chuàng)建文件輸入流 FileInputStream fileInputStream = new FileInputStream("NIOChannelTest.md"); FileChannel fileChannel = fileInputStream.getChannel(); ){ //定義一個(gè)ByteBuffer對(duì)象,用于重復(fù)取水 ByteBuffer bbuff = ByteBuffer.allocate(64); while(fileChannel.read(bbuff) != -1) { bbuff.flip(); Charset charset = Charset.forName("GBK"); //創(chuàng)建解碼器 CharsetDecoder decoder = charset.newDecoder(); //使用解碼器將ByteBuffer轉(zhuǎn)成CharBuffer CharBuffer charBuffer = decoder.decode(bbuff); System.out.println(charBuffer); //為下一次讀取數(shù)據(jù)做準(zhǔn)備 bbuff.clear(); } } }文件鎖
在NIO中,Java提供了文件鎖的支持,使用FileLock來(lái)支持文件鎖定功能,在FileChannel中提供lock()/tryLock()方法來(lái)獲取文件鎖FileLock對(duì)象,從而鎖定文件。lock和tryLock的區(qū)別是前者無(wú)法得到文件鎖的時(shí)候會(huì)阻塞,后者不會(huì)阻塞。也支持鎖定部分內(nèi)容,使用lock(long position, long size, boolean shared)即可,其中shared為true時(shí),表明該鎖是一個(gè)共享鎖,可以允許多個(gè)縣城讀取文件,但阻止其他進(jìn)程獲得該文件的排他鎖。當(dāng)shared為false時(shí),表明是一個(gè)排他鎖,它將鎖住對(duì)該文件的讀寫(xiě)。
默認(rèn)獲取的是排他鎖。
代碼示例
package com.wangjun.othersOfJava; import java.io.FileOutputStream; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; public class FileLockTest { public static void main(String[] args) throws Exception { try( FileOutputStream fos = new FileOutputStream("a.md"); FileChannel fc = fos.getChannel(); ){ //使用非阻塞方式對(duì)指定文件加鎖 FileLock lock = fc.tryLock(); Thread.sleep(3000); lock.release();//釋放鎖 } } }Java的NIO2
Java7對(duì)原來(lái)的NIO進(jìn)行了重大改進(jìn):
提供了全面的文件IO和文件系統(tǒng)訪問(wèn)支持;
基于異步Channel的IO。
這里先簡(jiǎn)單介紹一下對(duì)文件系統(tǒng)的支持,后續(xù)繼續(xù)學(xué)習(xí)。
NIO2提供了一下接口和工具類:
Path接口:通過(guò)和Paths工具類結(jié)合使用產(chǎn)生Path對(duì)象,可以獲取文件根路徑、絕對(duì)路徑、路徑數(shù)量等;
Files工具類:提供了很多靜態(tài)方法,比如復(fù)制文件、一次性讀取文件所有行、判斷是否為隱藏文件、判斷文件大小、遍歷文件和子目錄、訪問(wèn)文件屬性等;
FileVisitor接口:代表一個(gè)文件訪問(wèn)器,F(xiàn)iles工具類使用walkFileTree方法遍歷文件和子目錄時(shí),都會(huì)觸發(fā)FileVisitor中相應(yīng)的方法,比如訪問(wèn)目錄之前、之后,訪問(wèn)文件時(shí),訪問(wèn)文件失敗時(shí);
WatchService:監(jiān)控文件的變化;
NIO和IO的區(qū)別Java的NIO提供了與標(biāo)準(zhǔn)IO不同的工作方式:
Channels and Buffers(通道和緩沖區(qū)):標(biāo)準(zhǔn)的IO基于字節(jié)流和字符流進(jìn)行操作的,沒(méi)有被緩存在任何地方,而NIO是基于通道(Channel)和緩沖區(qū)(Buffer)進(jìn)行操作,數(shù)據(jù)總是從通道讀取到緩沖區(qū)中,或者從緩沖區(qū)寫(xiě)入到通道中,因此可以前后移動(dòng)流中的數(shù)據(jù);
Asynchronous IO(異步IO):Java NIO可以讓你異步的使用IO,例如:當(dāng)線程從通道讀取數(shù)據(jù)到緩沖區(qū)時(shí),線程還是可以進(jìn)行其他事情。當(dāng)數(shù)據(jù)被寫(xiě)入到緩沖區(qū)時(shí),線程可以繼續(xù)處理它。從緩沖區(qū)寫(xiě)入通道也類似。因?yàn)镹IO將阻塞交給了后臺(tái)線程執(zhí)行。而IO是阻塞的;
Selectors(選擇器):選擇器允許一個(gè)多帶帶的線程可以監(jiān)聽(tīng)多個(gè)數(shù)據(jù)通道((網(wǎng)絡(luò)連接或文件),你可以注冊(cè)多個(gè)通道使用一個(gè)選擇器,然后使用一個(gè)多帶帶的線程來(lái)“選擇”通道:這些通道里已經(jīng)有可以處理的輸入,或者選擇已準(zhǔn)備寫(xiě)入的通道。這種選擇機(jī)制,使得一個(gè)多帶帶的線程很容易來(lái)管理多個(gè)通道。但付出的代價(jià)是解析數(shù)據(jù)可能會(huì)比從一個(gè)阻塞流中讀取數(shù)據(jù)更復(fù)雜。?
使用場(chǎng)景NIO
優(yōu)勢(shì)在于一個(gè)線程管理多個(gè)通道;但是數(shù)據(jù)的處理將會(huì)變得復(fù)雜;
如果需要管理同時(shí)打開(kāi)的成千上萬(wàn)個(gè)連接,這些連接每次只是發(fā)送少量的數(shù)據(jù),采用這種;
傳統(tǒng)的IO
適用于一個(gè)線程管理一個(gè)通道的情況;因?yàn)槠渲械牧鲾?shù)據(jù)的讀取是阻塞的;
如果需要管理同時(shí)打開(kāi)不太多的連接,這些連接會(huì)發(fā)送大量的數(shù)據(jù);
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71093.html
摘要:異步可以讓你異步的使用,例如當(dāng)線程從通道讀取數(shù)據(jù)到緩沖區(qū)時(shí),線程還是可以進(jìn)行其他事情。當(dāng)數(shù)據(jù)被寫(xiě)入到緩沖區(qū)時(shí),線程可以繼續(xù)處理它。因此,單個(gè)的線程可以監(jiān)聽(tīng)多個(gè)數(shù)據(jù)通道。下面是系列文章的目錄概述通道之間的數(shù)據(jù)傳輸與原文譯者郭蕾校對(duì)方騰飛 Java NIO(New IO)是一個(gè)可以替代標(biāo)準(zhǔn)Java IO API的IO API(從Java 1.4開(kāi)始),Java NIO提供了與標(biāo)準(zhǔn)IO不同的...
摘要:線程之間的切換對(duì)于操作系統(tǒng)來(lái)說(shuō)是昂貴的。因此,單線程可以監(jiān)視多個(gè)通道中的數(shù)據(jù)。當(dāng)方法返回后,線程可以處理這些事件。 一 NIO簡(jiǎn)介 Java NIO 是 java 1.4 之后新出的一套IO接口,這里的的新是相對(duì)于原有標(biāo)準(zhǔn)的Java IO和Java Networking接口。NIO提供了一種完全不同的操作方式。 NIO中的N可以理解為Non-blocking,不單純是New。 它支持面...
摘要:從通道進(jìn)行數(shù)據(jù)寫(xiě)入創(chuàng)建一個(gè)緩沖區(qū),填充數(shù)據(jù),并要求通道寫(xiě)入數(shù)據(jù)。三之通道主要內(nèi)容通道介紹通常來(lái)說(shuō)中的所有都是從通道開(kāi)始的。從中選擇選擇器維護(hù)注冊(cè)過(guò)的通道的集合,并且這種注冊(cè)關(guān)系都被封裝在當(dāng)中停止選擇的方法方法和方法。 由于內(nèi)容比較多,我下面放的一部分是我更新在我的微信公眾號(hào)上的鏈接,微信排版比較好看,更加利于閱讀。每一篇文章下面我都把文章的主要內(nèi)容給列出來(lái)了,便于大家學(xué)習(xí)與回顧。 Ja...
摘要:簡(jiǎn)介是由引進(jìn)的異步由以下幾個(gè)核心部分組成和的對(duì)比和的區(qū)別主要體現(xiàn)在三個(gè)方面基于流而基于操作是阻塞的而操作是非阻塞的沒(méi)有概念而有概念基于與基于傳統(tǒng)的是面向字節(jié)流或字符流的而在中我們拋棄了傳統(tǒng)的流而是引入了和的概念在中我只能從中讀取數(shù)據(jù)到中或?qū)? 簡(jiǎn)介 Java NIO 是由 Java 1.4 引進(jìn)的異步 IO.Java NIO 由以下幾個(gè)核心部分組成: Channel Buffer Se...
摘要:學(xué)習(xí)和掌握技術(shù)已經(jīng)不是一個(gè)攻城獅的加分技能,而是一個(gè)必備技能。是雙向的,不僅可以讀取數(shù)據(jù)還能保存數(shù)據(jù),程序不能直接讀寫(xiě)通道,只與緩沖區(qū)交互為了讓大家不被高并發(fā)與大量連接處理問(wèn)題所困擾,動(dòng)力節(jié)點(diǎn)推出了高效處理模型應(yīng)用教程。 大家肯定了解Java IO, 但是對(duì)于NIO一般是陌生的,而現(xiàn)在使用到NIO的場(chǎng)景越來(lái)越多,很多技術(shù)框...
摘要:后改良為用線程池的方式代替新增線程,被稱為偽異步。最大的問(wèn)題是阻塞,同步。每次請(qǐng)求都由程序執(zhí)行并返回,這是同步的缺陷。這些都會(huì)被注冊(cè)在多路復(fù)用器上。多路復(fù)用器提供選擇已經(jīng)就緒狀態(tài)任務(wù)的能力。并沒(méi)有采用的多路復(fù)用器,而是使用異步通道的概念。 Netty是一個(gè)提供異步事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用框架,用以快速開(kāi)發(fā)高性能、高可靠的網(wǎng)絡(luò)服務(wù)器和客戶端程序。Netty簡(jiǎn)化了網(wǎng)絡(luò)程序的開(kāi)發(fā),是很多框架和公司...
閱讀 881·2021-11-22 09:34
閱讀 1017·2021-10-08 10:16
閱讀 1832·2021-07-25 21:42
閱讀 1799·2019-08-30 15:53
閱讀 3531·2019-08-30 13:08
閱讀 2190·2019-08-29 17:30
閱讀 3352·2019-08-29 17:22
閱讀 2184·2019-08-29 15:35