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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

快学Java NIO

發布時間:2025/7/14 java 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 快学Java NIO 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java NIO Tutorial 地址:http://tutorials.jenkov.com/java-nio/index.html

Java NIO系列教程譯文地址:http://ifeve.com/java-nio-all/

以下是我拜讀過程中摘抄的部分內容,并且加了一些內容、筆記,姑且叫《快學Java NIO》,方便以后再翻閱學習

附上一個Java NIO實現的demo,多人網絡聊天室

?

Java NIO 由以下幾個核心部分組成:

  • Channels
  • Buffers
  • Selectors

基本上,所有的 IO 在NIO 中都從一個Channel 開始。Channel 有點像流。 數據可以從Channel讀到Buffer中,也可以從Buffer 寫到Channel中。

?

Channel

FileChannel 從文件中讀寫數據。

DatagramChannel 能通過UDP讀寫網絡中的數據。

SocketChannel 能通過TCP讀寫網絡中的數據。

ServerSocketChannel可以監聽新進來的TCP連接,像Web服務器那樣。對每一個新進來的連接都會創建一個SocketChannel。

下面是一個FileChannel的示例

public class FileChannelTest {public static void main(String[] args) throws IOException {RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");FileChannel inChannel = aFile.getChannel();
//涉及到的buffer的方法稍后解釋ByteBuffer buf
= ByteBuffer.allocate(48);int bytesRead = inChannel.read(buf);while (bytesRead != -1) {//make buffer ready for read buf.flip();while (buf.hasRemaining()) {System.out.print((char) buf.get());// read 1 byte at a time}
buf.clear();//buf.compact();也可以bytesRead
= inChannel.read(buf);}aFile.close();} }

?

Buffer

為了理解Buffer的工作原理,需要熟悉它的三個屬性:

  • capacity
  • position
  • limit

在寫模式下,Buffer的limit表示你最多能往Buffer里寫多少數據。 寫模式下,limit等于Buffer的capacity。

當切換Buffer到讀模式時, limit表示你最多能讀到多少數據。因此,當切換Buffer到讀模式時,limit會被設置成寫模式下的position值。換句話說,你能讀到之前寫入的所有數據(limit被設置成已寫數據的數量,這個值在寫模式下就是position)

?

clear方法就是讓position設回0,limit與capacity相等。

  public final Buffer clear() {position = 0;limit = capacity;mark = -1;return this;}

?

flip方法將Buffer從寫模式切換到讀模式。調用flip()方法會將position設回0,并將limit設置成之前position的值。

  public final Buffer flip() {limit = position;position = 0;mark = -1;return this;}

?

compact()方法將所有未讀的數據拷貝到Buffer起始處。然后將position設到最后一個未讀元素正后面。limit屬性依然像clear()方法一樣,設置成capacity。現在Buffer準備好寫數據了,但是不會覆蓋未讀的數據。

  public ByteBuffer compact() {System.arraycopy(hb, ix(position()), hb, ix(0), remaining());position(remaining());limit(capacity());discardMark();return this;}

?

?Scatter/Gather

scatter/gather用于描述從Channel中讀取或者寫入到Channel的操作

分散(scatter)從Channel中讀取是指在讀操作時將讀取的數據寫入多個buffer中。因此,Channel將從Channel中讀取的數據“分散(scatter)”到多個Buffer中。
聚集(gather)寫入Channel是指在寫操作時將多個buffer的數據寫入同一個Channel,因此,Channel 將多個Buffer中的數據“聚集(gather)”后發送到Channel。

?

應用場景:例如傳輸一個由消息頭和消息體組成的消息,你可能會將消息體和消息頭分散到不同的buffer中,這樣你可以方便的處理消息頭和消息體

?

Scattering Reads在移動下一個buffer前,必須填滿當前的buffer,這也意味著它不適用于動態消息(譯者注:消息大小不固定)。

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

?

ByteBuffer header = ByteBuffer.allocate(128); ByteBuffer body = ByteBuffer.allocate(1024);//write data into buffers ByteBuffer[] bufferArray = { header, body };channel.write(bufferArray);

?

FileChannel的transferFrom()方法可以將數據從源通道傳輸到FileChannel中,下面是一個簡單的例子:

RandomAccessFile fromFile = new RandomAccessFile("data/fromFile.txt", "rw"); FileChannel fromChannel = fromFile.getChannel();RandomAccessFile toFile = new RandomAccessFile("data/toFile.txt", "rw"); FileChannel toChannel = toFile.getChannel();long position = 0; long count = fromChannel.size();//toChannel.transferFrom(fromChannel, position, count);也可以 fromChannel.transferTo(position, count, toChannel);

?

Selector

Selector(選擇器)是Java NIO中能夠檢測一到多個NIO通道,并能夠知曉通道是否為諸如讀寫事件做好準備的組件。這樣,一個單獨的線程可以管理多個channel,從而管理多個網絡連接,Selector能夠處理多個通道。

?

Selector selector = Selector.open();
//FileChannel不能切換到非阻塞模式,所以這邊不能使FileChannel channel.configureBlocking(
false);//與Selector一起使用時,Channel必須處于非阻塞模式下 SelectionKey key = channel.register(selector, SelectionKey.OP_READ); //除了注冊讀,還可以注冊connect,accept,read,write事件 while(true) {int readyChannels = selector.select(); //阻塞到至少有一個通道就緒,還有select(long timeout)超時就不阻塞,selectNow()不阻塞,沒有就返回0,當然打斷阻塞還有wakeUp()方法,可以用另外一個線程調用這個方法,操作同一個selector對象即可if(readyChannels == 0) continue; Set selectedKeys = selector.selectedKeys(); //可以通過這個方法,知道可用通道的集合Iterator keyIterator = selectedKeys.iterator();while(keyIterator.hasNext()) {SelectionKey key = keyIterator.next();if(key.isAcceptable()) {// a connection was accepted by a ServerSocketChannel.
     //SelectionKey.channel()方法返回的通道需要轉型成你要處理的類型,如ServerSocketChannel或SocketChannel等
} else if (key.isConnectable()) {// a connection was established with a remote server.} else if (key.isReadable()) {// a channel is ready for reading} else if (key.isWritable()) {// a channel is ready for writing }
  //Selector不會自己從已選擇鍵集中移除SelectionKey實例。必須在處理完通道時自己移除。下次該通道變成就緒時,Selector會再次將其放入已選擇鍵集中。keyIterator.remove();} }

?

現在能看到的情況是,一個請求過來,到Selector這邊,selector從注冊的通道中選擇就緒的通道,然后找到具體的通道處理這個請求。

用一個selector線程來安排所有的channel!

當然為了并發,可以用多個selector,然后不同的channel來注冊。這樣就有了反向代理的感覺,selector就是反向代理服務器上的線程!

(以上是我個人對selector的理解,若理解有誤,請指正)

?

Java NIO與IO

我應該何時使用IO,何時使用NIO呢?在本文中,我會盡量清晰地解析Java NIO和IO的差異、它們的使用場景,以及它們如何影響您的代碼設計。

?

Java NIO與IO之間主要差別

IO NIO 面向流 面向緩沖 阻塞IO 非阻塞IO 無 選擇器

Java NIO的緩沖導向方法是數據讀取到一個它稍后處理的緩沖區,需要時可在緩沖區中前后移動,這就增加了處理過程中的靈活性。NIO設計中多了buffer,傳統IO如果要這個效果,需要自行定義操作buffer。

Java NIO的非阻塞模式,使一個線程從某通道發送請求讀取數據,但是它僅能得到目前可用的數據,如果目前沒有數據可用時,就什么都不會獲取。

Java NIO的選擇器允許一個單獨的線程來監視多個輸入通道,你可以注冊多個通道使用一個選擇器。

?

在IO設計中,我們從InputStream或 Reader逐字節讀取數據。?readline()阻塞直到整行讀完

NIO可讓您只使用一個(或幾個)單線程管理多個通道(網絡連接或文件),但付出的代價是解析數據可能會比從一個阻塞流中讀取數據更復雜。

?

如果需要管理同時打開的成千上萬個連接,這些連接每次只是發送少量的數據,例如聊天服務器,實現NIO的服務器可能是一個優勢。

如果你需要維持許多打開的連接到其他計算機上,如P2P網絡中,使用一個單獨的線程來管理你所有出站連接,可能是一個優勢。

Java NIO: 單線程管理多個連接,如下圖

如果你有少量的連接使用非常高的帶寬,一次發送大量的數據,也許典型的IO服務器實現可能非常契合。

Java IO: 一個典型的IO服務器設計- 一個連接通過一個線程處理,如下圖

至此,基本上Java NIO的大體輪廓已經明白了,鑒于篇幅不要太長,各個具體Channel的介紹移步:快學Java NIO續篇

  • FileChannel
  • SocketChannel
  • ServerSocketChannel
  • Java NIO DatagramChannel
  • Pipe

?

?

?

?

轉載于:https://www.cnblogs.com/yanghuahui/p/3683600.html

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的快学Java NIO的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。