日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

NIO笔记

發(fā)布時(shí)間:2025/6/17 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NIO笔记 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

JAVA NIO,是區(qū)別于JAVA IO的NEW IO。和普通的IO存在一定的區(qū)別,先記下這么幾個(gè)字吧:

走通道,用緩存,選擇器,非阻塞


走通道

NIO有三大組成:Channel(通道)、Buffer(緩存)、Selector(選擇器)
其中通道是指的實(shí)現(xiàn)java.nio.channels.Channel接口的對(duì)象,常見的對(duì)象有以下幾種:

FileChannel(文件通道)
DatagramChannel(收發(fā)UDP包的通道)
SocketChannel(連接到TCP網(wǎng)絡(luò)套接字的通道)
ServerSocketChannel(可以監(jiān)聽新進(jìn)來的TCP連接的通道)

相比較于IO的時(shí)候,輸入輸出需要用InputStream,OutputStream兩種,NIO的的通道只有一種,以FileChannel為例。
打開:

RandomAccessFile aFile = new RandomAccessFile("xxx.txt", "rw"); FileChannel inChannel = aFile.getChannel();

讀取:

ByteBuffer buf = ByteBuffer.allocate(48); // nio的buffer int bytesRead = inChannel.read(buf); // 初始化寫入到buffer while (bytesRead != -1) {buf.flip(); // 切換讀寫模式while(buf.hasRemaining()){System.out.print((char) buf.get()); // 讀取buff的內(nèi)容}buf.clear(); // buffer清空,使之可以再次寫入bytesRead = inChannel.read(buf); // 寫入到buffer }

寫入:

inChannel.write(buf);

可以看到,使用FileChannel不管是讀取還是寫入,都是使用了ByteBuffer作為中轉(zhuǎn),這個(gè)ByteBuffer,就是NIO中的緩存了。


用緩存

緩存類型:

緩存是實(shí)現(xiàn)了java.nio.Buffer抽象類接口的對(duì)象。
對(duì)于部分IO來說,其對(duì)象內(nèi)部也存在緩存,但都是對(duì)象的成員變量,而NIO中的,緩存需要單獨(dú)使用,走【數(shù)據(jù)】->【緩存】->【通道】->【對(duì)象】,或者【對(duì)象】->【通道】->【緩存】->【數(shù)據(jù)】的方式,進(jìn)行數(shù)據(jù)的流通。
緩存有很多種,除了boolean以外,基本類型全部包括。個(gè)人感覺有的類似于ObjectInputStream中writeByte、writeInt等等的方法,把這些方法抽象為一個(gè)對(duì)象的感覺。

ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer

例子:

首先,可以看到,java.nio.Buffer的源碼中的以下記得成員,這是buffer的關(guān)鍵:

private int position = 0; private int limit; private int capacity;

其中:

capacity:內(nèi)存塊,初始化時(shí)設(shè)置,限制緩存空間大小。
position:當(dāng)前位置。寫模式時(shí)初始為零,寫一次移動(dòng)一下。切換到讀模式時(shí),重置為0。position最大可為capacity – 1。
limit:寫模式時(shí),同capacity,一次寫入大小。切換到讀模式時(shí), limit表示你最多能讀到多少數(shù)據(jù),此時(shí),limit會(huì)被設(shè)置成寫模式下的position值。

聚集和分散:

簡單的說,buffer使用的時(shí)候,可以一個(gè)數(shù)組一起使用,這種使用方式類似水流,先填滿一個(gè),再填滿另一個(gè)。
Scattering Reads(聚集)是指數(shù)據(jù)從一個(gè)channel讀取到多個(gè)buffer中。

ByteBuffer header = ByteBuffer.allocate(128); ByteBuffer body = ByteBuffer.allocate(1024); ByteBuffer[] bufferArray = { header, body }; channel.read(bufferArray);

read()方法按照buffer在數(shù)組中的順序?qū)腸hannel中讀取的數(shù)據(jù)寫入到buffer,當(dāng)一個(gè)buffer被寫滿后,channel緊接著向另一個(gè)buffer中寫。

Gathering Writes(分散)是指數(shù)據(jù)從多個(gè)buffer寫入到同一個(gè)channel。

channel.write(bufferArray);

使用緩存:

初始化:使用allocate方法,設(shè)定capacity以初始化

ByteBuffer byteBuf = ByteBuffer.allocate(48);

寫入緩存:直降使用緩存的put方法,或者使用通道的read方法進(jìn)行寫入

inChannel.read(buf); // 通道寫入到bufferbuf.put(100); // put寫入

模式切換:寫入后,進(jìn)行讀取時(shí),需要調(diào)用flip()方法,進(jìn)行模式切換(實(shí)際是改變position位置)

buf.flip(); // 切換讀寫模式

重置:讀取后想重新讀取,使用rewind()方法。

buf.rewind(); // buffer重置,使之可以再次讀取

清空:想要再次寫入,或者清空寫入內(nèi)容時(shí),使用clear()方法
buf.clear(); // buffer清空,使之可以再次寫入


選擇器

選擇器即Selector,簡單的說,就是用于管理多個(gè)Channel的對(duì)象,感覺有的類似于線程池,但Selector確實(shí)是單線程對(duì)象,通過注冊(cè)->接收->處理的過程,對(duì)多個(gè)Channel進(jìn)行管理。
其中將【選擇器】同【通道】關(guān)聯(lián)起來的線,即為選擇鍵,SelectionKey。
總之先記著,選擇器使用靜態(tài)實(shí)例創(chuàng)建,使用注冊(cè)通道返回選擇鍵的方式進(jìn)行關(guān)聯(lián)。

Selector Selector=Selector.open(); // 創(chuàng)建實(shí)例 channel.configureBlocking(false); // 通道設(shè)置非阻塞,不然同Selector一起用會(huì)異常(FileChannel不能設(shè)非阻塞) SelectionKey key= channel.register(selector,SelectionKey.OP_ACCEPT); // 通道注冊(cè)

SelectionKey.OP_ACCEPT標(biāo)識(shí),是Selector要監(jiān)視通道的那些動(dòng)作。當(dāng)通道的動(dòng)作處在就緒狀態(tài)時(shí),Selector監(jiān)視到,然后可進(jìn)行操作。

關(guān)于SelectionKey,既然是Channel和Selector的管理,那么進(jìn)行操作的時(shí)候,也是對(duì)SelectionKey進(jìn)行操作了。可以使用isAcceptable(),isConnectable(),isReadable(),isWritable(),來判斷Channel的是否可以進(jìn)行對(duì)應(yīng)的操作。isValid判斷是否有數(shù)據(jù)(緩存)。attach來進(jìn)行綁定和解綁等等。
因此,一般Selector的使用方式是弄個(gè)循環(huán),使用selector.selectedKeys()的方法渠道所有就緒,能操作的SelectionKey,如下:

while(true){ // 循環(huán)內(nèi)Set selectedKeys = selector.selectedKeys(); // 取得可操作SelectionKey集合Iterator keyIterator = selectedKeys.iterator();while(keyIterator.hasNext()) {SelectionKey key = keyIterator.next(); // 取得SelectionKey,并判斷不同的狀態(tài)進(jìn)行操作if(key.isAcceptable()) {...} else if (key.isConnectable()) {...} else if (key.isReadable()) {...} else if (key.isWritable()) {...}keyIterator.remove();} }

非阻塞

由于是同步非阻塞的,所以其原理基本上就是在設(shè)置好之后,利用循環(huán)不斷遍歷Channel,判斷其狀態(tài),有可操作的地方就處理,沒有則繼續(xù)判斷而已。
其中,由于使用了緩存通道分離的方式,最大的優(yōu)勢(shì)在于當(dāng)有可進(jìn)行的操作的時(shí)候,實(shí)際上通道已經(jīng)準(zhǔn)備就緒,可以立即執(zhí)行,省去了讀取的時(shí)間。如下,其他方法時(shí),以下read的時(shí)候,會(huì)阻塞花費(fèi)較多時(shí)間。而NIO的時(shí)候,由于已經(jīng)換成,會(huì)馬上讀取完畢,可執(zhí)行下面的操作。

SocketChannel socketChannel = (SocketChannel) key.channel(); int len = socketChannel.read(readBuffer); // **這里**

轉(zhuǎn)載于:https://www.cnblogs.com/changfanchangle/p/9092450.html

總結(jié)

以上是生活随笔為你收集整理的NIO笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。