摘要:組件主要有三大核心部分通道,緩沖區選擇器。選擇區用于監聽多個通道的事件比如連接打開,數據到達。即用選擇器,借助單一線程,就可對數量龐大的活動通道實施監控和維護。
Java NIO 簡介
JAVA NIO有兩種解釋:一種叫非阻塞IO(Non-blocking I/O),另一種也叫新的IO(New I/O),其實是同一個概念。它是一種同步非阻塞的I/O模型,也是I/O多路復用的基礎,已經被越來越多地應用到大型應用服務器,成為解決高并發與大量連接、I/O處理問題的有效方式。
NIO是一種基于通道和緩沖區的I/O方式,它可以使用Native函數庫直接分配堆外內存(區別于JVM的運行時數據區),然后通過一個存儲在java堆里面的DirectByteBuffer對象作為這塊內存的直接引用進行操作。這樣能在一些場景顯著提高性能,因為避免了在Java堆和Native堆中來回復制數據。
Java NIO組件
NIO主要有三大核心部分:Channel(通道),Buffer(緩沖區), Selector(選擇器)。傳統IO是基于字節流和字符流進行操作(基于流),而NIO基于Channel和Buffer(緩沖區)進行操作,數據總是從通道讀取到緩沖區中,或者從緩沖區寫入到通道中。Selector(選擇區)用于監聽多個通道的事件(比如:連接打開,數據到達)。因此,單個線程可以監聽多個數據通道。
Buffer
Buffer(緩沖區)是一個用于存儲特定基本類型數據的容器。除了boolean外,其余每種基本類型都有一個對應的buffer類。Buffer類的子類有ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer 。
Channel
Channel(通道)表示到實體,如硬件設備、文件、網絡套接字或可以執行一個或多個不同 I/O 操作(如讀取或寫入)的程序組件的開放的連接。Channel接口的常用實現類有FileChannel(對應文件IO)、DatagramChannel(對應UDP)、SocketChannel和ServerSocketChannel(對應TCP的客戶端和服務器端)。Channel和IO中的Stream(流)是差不多一個等級的。只不過Stream是單向的,譬如:InputStream, OutputStream.而Channel是雙向的,既可以用來進行讀操作,又可以用來進行寫操作。
Selector
Selector(選擇器)用于監聽多個通道的事件(比如:連接打開,數據到達)。因此,單個的線程可以監聽多個數據通道。即用選擇器,借助單一線程,就可對數量龐大的活動I/O通道實施監控和維護。
Java NIO的簡單實現
public class Demo1 { private static Integer port = 8080; // 通道管理器(Selector) private static Selector selector; private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 10, 1000, TimeUnit.MILLISECONDS, new LinkedTransferQueue<>(), new ThreadPoolExecutor.AbortPolicy()); public static void main(String[] args) { try { // 創建通道ServerSocketChannel ServerSocketChannel open = ServerSocketChannel.open(); // 將通道設置為非阻塞 open.configureBlocking(false); // 綁定到指定的端口上 open.bind(new InetSocketAddress(port)); // 通道管理器(Selector) selector = Selector.open(); /** * 將通道(Channel)注冊到通道管理器(Selector),并為該通道注冊selectionKey.OP_ACCEPT事件 * 注冊該事件后,當事件到達的時候,selector.select()會返回, * 如果事件沒有到達selector.select()會一直阻塞。 */ open.register(selector, SelectionKey.OP_ACCEPT); // 循環處理 while (true) { /** * 當注冊事件到達時,方法返回,否則該方法會一直阻塞 * 該Selector的select()方法將會返回大于0的整數,該整數值就表示該Selector上有多少個Channel具有可用的IO操作 */ int select = selector.select(); System.out.println("當前有 " + select + " 個channel可以操作"); // 一個SelectionKey對應一個就緒的通道 SetselectionKeys = selector.selectedKeys(); Iterator iterator = selectionKeys.iterator(); while (iterator.hasNext()) { // 獲取事件 SelectionKey key = iterator.next(); // 移除事件,避免重復處理 iterator.remove(); // 客戶端請求連接事件,接受客戶端連接就緒 if (key.isAcceptable()) { accept(key); } else if (key.isReadable()) { // 監聽到讀事件,對讀事件進行處理 threadPoolExecutor.submit(new NioServerHandler(key)); } } } } catch (IOException e) { e.printStackTrace(); } } /** * 處理客戶端連接成功事件 * * @param key */ public static void accept(SelectionKey key) { try { // 獲取客戶端連接通道 ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); SocketChannel sc = ssc.accept(); sc.configureBlocking(false); // 給通道設置讀事件,客戶端監聽到讀事件后,進行讀取操作 sc.register(selector, SelectionKey.OP_READ); System.out.println("accept a client : " + sc.socket().getInetAddress().getHostName()); } catch (IOException e) { e.printStackTrace(); } } /** * 監聽到讀事件,讀取客戶端發送過來的消息 */ public static class NioServerHandler implements Runnable { private SelectionKey selectionKey; public NioServerHandler(SelectionKey selectionKey) { this.selectionKey = selectionKey; } @Override public void run() { try { if (selectionKey.isReadable()) { SocketChannel socketChannel = (SocketChannel) selectionKey.channel(); // 從通道讀取數據到緩沖區 ByteBuffer buffer = ByteBuffer.allocate(1024); // 輸出客戶端發送過來的消息 socketChannel.read(buffer); buffer.flip(); System.out.println("收到客戶端" + socketChannel.socket().getInetAddress().getHostName() + "的數據:" + new String(buffer.array())); //將數據添加到key中 ByteBuffer outBuffer = ByteBuffer.wrap(buffer.array()); // 將消息回送給客戶端 socketChannel.write(outBuffer); selectionKey.cancel(); } } catch (IOException e) { e.printStackTrace(); } } } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/75111.html
摘要:前言本篇主要講解中的機制和網絡通訊中處理高并發的分為兩塊第一塊講解多線程下的機制第二塊講解如何在機制下優化資源的浪費服務器單線程下的機制就不用我介紹了,不懂得可以去查閱下資料那么多線程下,如果進行套接字的使用呢我們使用最簡單的服務器來幫助大 前言 本篇主要講解Java中的IO機制和網絡通訊中處理高并發的NIO 分為兩塊:第一塊講解多線程下的IO機制第二塊講解如何在IO機制下優化CPU資...
摘要:什么是零拷貝我們首先來認識一下傳統的操作。因為在這套體系里,不僅僅提供了非阻塞的編程模型,而且提供了類似零拷貝,內存映射這樣的新技術對于操作系統來說早就有了。 什么是零拷貝?我們首先來認識一下傳統的I/O操作。假如說用戶進程現在要把一個文件復制到另一個地方。那么用戶程序必須先把這個文件讀入內存,然后再把內存里的數據寫入另一個文件。不過文件讀入內存也不是直接讀入用戶進程的內存,而是先讀入...
摘要:的異步即是異步的,也是非阻塞的。但是,也可以進行一層稍微薄點的封裝,保留這種多路復用的模型,比如的,是一種同步非阻塞的模型。系統調用操作系統的系統調用提供了多路復用的非阻塞的系統調用,這也是機制實現需要用到的。 異步IO編程在javascript中得到了廣泛的應用,之前也寫過一篇博文進行梳理。js的異步IO即是異步的,也是非阻塞的。非阻塞的IO需要底層操作系統的支持,比如在linux上...
摘要:而用于主線程池的屬性都定義在中本篇只是簡單介紹了一下引導類的配置屬性,下一篇我將詳細介紹服務端引導類的過程分析。 從Java1.4開始, Java引入了non-blocking IO,簡稱NIO。NIO與傳統socket最大的不同就是引入了Channel和多路復用selector的概念。傳統的socket是基于stream的,它是單向的,有InputStream表示read和Outpu...
摘要:通道可以異步讀寫。使用的方法讀取數據創建一個讀數據緩沖區對象從通道中讀取數據使用的方法寫入數據創建一個寫數據緩沖區對象寫入數據關閉完成使用后,您必須關閉它。五提供了一種被稱為的新功能,也稱為本地矢量。功能是通道提供的并不是。 歷史回顧: Java NIO 概覽 Java NIO 之 Buffer(緩沖區) 其他高贊文章: 面試中關于Redis的問題看這篇就夠了 一文輕松搞懂redis集...
閱讀 2949·2021-10-28 09:32
閱讀 2980·2021-10-11 10:57
閱讀 3125·2021-10-08 10:05
閱讀 2606·2021-09-28 09:36
閱讀 2221·2019-08-30 15:55
閱讀 2276·2019-08-30 15:44
閱讀 2401·2019-08-30 14:02
閱讀 3082·2019-08-29 17:16