国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
Java中BIO,NIO和AIO使用樣例

上文中分析了阻塞,非阻塞,同步和異步概念上的區(qū)別以及各種IO模型的操作流程,本篇文章將主要介紹Java中BIO,NIO和AIO三種IO模型如何使用。需要注意的是,本文中所提到的所有樣例都是在一個(gè)server對(duì)應(yīng)一個(gè)client的情況下工作的,如果你想擴(kuò)展為一個(gè)server服務(wù)多個(gè)client,那么代碼需要做相應(yīng)的修改才能使用。另外,本文只會(huì)講解server端如何處理,客戶端的操作流程可以仿照服務(wù)端進(jìn)行編程,大同小異。文章最后給出了源碼的下載地址。

BIO(Blocking I/O)

在Java中,BIO是基于流的,這個(gè)流包括字節(jié)流或者字符流,但是細(xì)心的同學(xué)可能會(huì)發(fā)現(xiàn)基本上所有的流都是單向的,要么只讀,要么只寫(xiě)。在實(shí)際上編程時(shí),在對(duì)IO操作之前,要先獲取輸入流或輸出流,然后對(duì)輸入流讀或?qū)敵隽鲗?xiě)即完成實(shí)際的IO讀寫(xiě)操作。首先需要新建一個(gè)ServerSocket對(duì)象監(jiān)聽(tīng)特定端口,然后當(dāng)有客戶端的連接請(qǐng)求到來(lái)時(shí),在服務(wù)器端獲取一個(gè)Socket對(duì)象,用來(lái)進(jìn)行實(shí)際的通信。

ServerSocket serverSocket = new ServerSocket(PORT);  Socket socket = serverSocket.accept();  

獲取到Socket對(duì)象后,通過(guò)這個(gè)Socket對(duì)象拿到輸入流和輸出流就可以進(jìn)行相應(yīng)的讀寫(xiě)操作了。

DataInputStream in = new DataInputStream(socket.getInputStream());  DataOutputStream out = new DataOutputStream(socket.getOutputStream());  

由于BIO的編程的模型比較簡(jiǎn)單,這里就寫(xiě)這么多,需要下載源代碼的可以到文章末尾。

NIO(New I/O, or Nonblocking I/O)

BIO的編程模型簡(jiǎn)單易行,但是缺點(diǎn)也很明顯。由于采用的是同步阻塞IO的模式,所以server端要為每一個(gè)連接創(chuàng)建一個(gè)線程,一方面,線程之間在進(jìn)行上下文切換的時(shí)候會(huì)造成比較大的開(kāi)銷(xiāo),另一方面,當(dāng)連接數(shù)過(guò)多時(shí),可能會(huì)造成服務(wù)器崩潰的現(xiàn)象產(chǎn)生。

為了解決這個(gè)問(wèn)題,在JDK 1.4的時(shí)候,引入了NIO(New IO)的概念。NIO主要由三個(gè)部分組成,即Channel,BufferSelector。Channel可以跟BIO中的Stream類(lèi)比,不同的是Channel是可讀可寫(xiě)的。當(dāng)和Channel進(jìn)行交互的時(shí)候需要Buffer的支持,數(shù)據(jù)可以從Buffer寫(xiě)到Channel中,也可以從Channel中讀到Buffer中,他們的關(guān)系如下圖。

以SocketChannel為例,Channel和Buffer交互的例子如下。ByteBuffer是Buffer的一種實(shí)現(xiàn),在使用ByteBuffer之前,需要為其分配空間,然后調(diào)用Channel的read方法將數(shù)據(jù)寫(xiě)入Buffer中,在完成后,在使用Buffer中的數(shù)據(jù)之前需要調(diào)用Buffer的flip方法。Buffer中有個(gè)position常量,記錄當(dāng)前操作數(shù)據(jù)的位置,當(dāng)向Buffer中寫(xiě)數(shù)據(jù)時(shí),position會(huì)記錄當(dāng)前寫(xiě)的位置,當(dāng)寫(xiě)操作完成后,flip會(huì)把position至為0,這樣讀取Buffer中的數(shù)據(jù)時(shí),就會(huì)從0開(kāi)始了。另外需要注意的是處理完Buffer中的數(shù)據(jù)后需要調(diào)用clear方法將Buffer清空。向Channel中寫(xiě)數(shù)據(jù)的操作比較簡(jiǎn)單,這里不再贅述。

// Read data from channel to bufferSocketChannel socketChannel = (SocketChannel) selectionKey.channel();  ByteBuffer byteBuffer = ByteBuffer.allocate(1024);  while (socketChannel.read(byteBuffer) > 0) {      byteBuffer.flip();    while(byteBuffer.hasRemaining()){        System.out.print((char) byteBuffer.get());    }    byteBuffer.clear();}// Write data to channel from buffersocketChannel.write(ByteBuffer.wrap(msg.getBytes()));  

NIO中另一個(gè)重要的組件是Selector,Selector可以用來(lái)檢查一個(gè)或多個(gè)Channel是否有新的數(shù)據(jù)到來(lái),這種方式可以實(shí)現(xiàn)在一個(gè)線程中管理多個(gè)Channel的目的,示意圖如下。

在使用selector之前,一定要注意把對(duì)應(yīng)的Channel配置為非阻塞。否則在注冊(cè)的時(shí)候會(huì)拋異常。

serverSocketChannel.configureBlocking(false);  

然后調(diào)用select函數(shù),select是個(gè)阻塞函數(shù),它會(huì)阻塞直到某一個(gè)操作被激活。這個(gè)時(shí)候可以獲取一系列的SelectionKey,通過(guò)這個(gè)SelectionKey可以判斷其對(duì)應(yīng)的Channel可進(jìn)行的操作(可讀,可寫(xiě)或者可接受連接),然后進(jìn)行相應(yīng)的操作即可。這里還要注意一個(gè)問(wèn)題就是在判斷完可執(zhí)行的操作后,需要將這個(gè)SelectionKey從集合中移除

selector.select();Set<SelectionKey> selectionKeys = selector.selectedKeys();  Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {      SelectionKey selectionKey = iterator.next();    if (!selectionKey.isValid())        continue;    if (selectionKey.isAcceptable()) {        // ready for accepting            } else if (selectionKey.isReadable()) {        // ready for reading                       } else if (selectionKey.isWritable()) {        // ready for writing    }    iterator.remove();}

NIO這里最后一個(gè)問(wèn)題是,什么時(shí)候Channel可寫(xiě),這個(gè)問(wèn)題困擾了我很久,經(jīng)過(guò)從網(wǎng)上查資料最后得出的結(jié)論是,只要這個(gè)Channel處于空閑狀態(tài),都是可寫(xiě)的。這個(gè)我也從實(shí)際的程序中論證了。

AIO(Asynchronous I/O)

在JDK 1.7時(shí),Java引入了AIO的概念,AIO還是基于Channel和Buffer的,不同的是它是異步的。用戶線程把實(shí)際的IO操作以及數(shù)據(jù)拷貝全部委托給內(nèi)核來(lái)做,用戶只要傳遞給內(nèi)核一個(gè)用于存儲(chǔ)數(shù)據(jù)的地址空間即可。內(nèi)核處理的結(jié)果通過(guò)兩種方式返回給用戶線程。一是通過(guò)Future對(duì)象,另外一種是通過(guò)回調(diào)函數(shù)的方式,回調(diào)函數(shù)需要實(shí)現(xiàn)CompletionHandler接口。這里只給出通過(guò)回調(diào)方式處理數(shù)據(jù)的樣例,其中關(guān)鍵的步驟已經(jīng)在程序中添加了注釋。

// 創(chuàng)建AsynchronousServerSocketChannel監(jiān)聽(tīng)特定端口,并設(shè)置回調(diào)AcceptCompletionHandlerAsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(PORT));  serverSocketChannel.accept(serverSocketChannel, new AcceptCompletionHandler());// 監(jiān)聽(tīng)回調(diào),當(dāng)用連接時(shí)會(huì)觸發(fā)該回調(diào)private static class AcceptCompletionHandler implements CompletionHandler<AsynchronousSocketChannel, AsynchronousServerSocketChannel> {      @Override    public void completed(AsynchronousSocketChannel result, AsynchronousServerSocketChannel attachment) {        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);        // 注冊(cè)read請(qǐng)求以及回調(diào)ReadCompletionHandler        result.read(byteBuffer, result, new ReadCompletionHandler(byteBuffer, "client"));        // 遞歸監(jiān)聽(tīng)        attachment.accept(attachment, this);    }    @Override    public void failed(Throwable exc, AsynchronousServerSocketChannel attachment) {        // 遞歸監(jiān)聽(tīng)        attachment.accept(attachment, this);    }}// 讀取數(shù)據(jù)回調(diào),當(dāng)有數(shù)據(jù)可讀時(shí)觸發(fā)該回調(diào)public class ReadCompletionHandler  implements CompletionHandler<Integer, AsynchronousSocketChannel> {      private ByteBuffer byteBuffer;    private String remoteName;    public ReadCompletionHandler(ByteBuffer byteBuffer, String remoteName) {        this.byteBuffer = byteBuffer;        this.remoteName = remoteName;    }    @Override    public void completed(Integer result, AsynchronousSocketChannel attachment) {        if (result <= 0)            return;        byteBuffer.flip();        System.out.println("[" + this.remoteName + "] " + new String(byteBuffer.array()));        byteBuffer.clear();        // 遞歸監(jiān)聽(tīng)數(shù)據(jù)        attachment.read(byteBuffer, attachment, this);    }    @Override    public void failed(Throwable exc, AsynchronousSocketChannel attachment) {        byteBuffer.clear();        // 遞歸監(jiān)聽(tīng)數(shù)據(jù)        attachment.read(byteBuffer, attachment, this);    }}

上面給出了BIO,NIO以及AIO在Java中的使用的部分程序,并且分析了其中關(guān)鍵步驟的使用及其需要注意的事項(xiàng)。

需要源碼的同學(xué)可以到這里下載。

參考

Java NIO Tutorial

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
聊聊BIO、NIO與AIO的區(qū)別
「每日分享」網(wǎng)絡(luò)編程-NIO、BIO、AIO詳解
高并發(fā)Java(8):NIO和AIO(下)
使用Java NIO編寫(xiě)高性能的服務(wù)器
Java NIO API詳解
Java NIO與IO的區(qū)別和比較
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服