Java中的同步非阻塞IO模型詳解
介紹
IO模型中的,同步非阻塞IO模型,我們能夠知道,用戶線程一直發(fā)送請(qǐng)求,內(nèi)核一直都能都?jí)蚍祷?,直到內(nèi)核完成準(zhǔn)備數(shù)據(jù)、數(shù)據(jù)拷貝的工作。
并且返回成功的指示。在此過程中用戶線程不是阻塞的狀態(tài)
實(shí)現(xiàn)
使用java來實(shí)現(xiàn)同步非阻塞IO模型,即我們所說的NIO的模型
客戶端實(shí)現(xiàn)
/** * @author:triumphxx * @Date:2021/11/12 * @Time:11:03 下午 * @微信公眾號(hào):北漂碼農(nóng)有話說 * @網(wǎng)站:http://blog.triumphxx.com.cn * @GitHub https://github.com/triumphxx * @Desc: NIO編程模型客戶端 **/ public class NIOClient { // 通道管理器(Selector) private static Selector selector; public static void main(String[] args) throws IOException { // 創(chuàng)建通道管理器(Selector) selector = Selector.open(); // 創(chuàng)建通道SocketChannel SocketChannel channel = SocketChannel.open(); // 將通道設(shè)置為非阻塞 channel.configureBlocking(false); // 客戶端連接服務(wù)器,其實(shí)方法執(zhí)行并沒有實(shí)現(xiàn)連接,需要在handleConnect方法中調(diào)channel.finishConnect()才能完成連接 channel.connect(new InetSocketAddress("localhost", 9090)); /** * 將通道(Channel)注冊(cè)到通道管理器(Selector),并為該通道注冊(cè)selectionKey.OP_CONNECT * 注冊(cè)該事件后,當(dāng)事件到達(dá)的時(shí)候,selector.select()會(huì)返回, * 如果事件沒有到達(dá)selector.select()會(huì)一直阻塞。 */ channel.register(selector, SelectionKey.OP_CONNECT); // 循環(huán)處理 while (true) { /* * 選擇一組可以進(jìn)行I/O操作的事件,放在selector中,客戶端的該方法不會(huì)阻塞, * selector的wakeup方法被調(diào)用,方法返回,而對(duì)于客戶端來說,通道一直是被選中的 * 這里和服務(wù)端的方法不一樣,查看api注釋可以知道,當(dāng)至少一個(gè)通道被選中時(shí)。 */ selector.select(); // 獲取監(jiān)聽事件 Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = selectionKeys.iterator(); // 迭代處理 while (iterator.hasNext()) { // 獲取事件 SelectionKey key = iterator.next(); // 移除事件,避免重復(fù)處理 iterator.remove(); // 檢查是否是一個(gè)就緒的已經(jīng)連接服務(wù)端成功事件 if (key.isConnectable()) { handleConnect(key); } else if (key.isReadable()) {// 檢查套接字是否已經(jīng)準(zhǔn)備好讀數(shù)據(jù) handleRead(key); } } } } /** * 處理客戶端連接服務(wù)端成功事件 */ private static void handleConnect(SelectionKey key) throws IOException { // 獲取與服務(wù)端建立連接的通道 SocketChannel channel = (SocketChannel) key.channel(); if (channel.isConnectionPending()) { // channel.finishConnect()才能完成連接 channel.finishConnect(); } channel.configureBlocking(false); // 數(shù)據(jù)寫入通道 String msg = "Hello Server!"; channel.write(ByteBuffer.wrap(msg.getBytes())); // 通道注冊(cè)到選擇器,并且這個(gè)通道只對(duì)讀事件感興趣 channel.register(selector, SelectionKey.OP_READ); } /** * 監(jiān)聽到讀事件,讀取客戶端發(fā)送過來的消息 */ private static void handleRead(SelectionKey key) throws IOException { SocketChannel channel = (SocketChannel) key.channel(); //開辟堆內(nèi)緩沖區(qū) ByteBuffer buffer = ByteBuffer.allocate(128); // 從通道讀取數(shù)據(jù)到緩沖區(qū) channel.read(buffer); // 輸出服務(wù)端響應(yīng)發(fā)送過來的消息 byte[] data = buffer.array(); String msg = new String(data).trim(); System.out.println("服務(wù)端發(fā)來的消息:" + msg); } }
由客戶端的代碼可以知道:首先我們將 select 打開,然后創(chuàng)建通道、將通道設(shè)置為非阻塞、創(chuàng)建連接、完成注冊(cè) 等待監(jiān)聽、處理事件,詳細(xì)的每一行代碼的意思,都已經(jīng)進(jìn)展標(biāo)注。看代碼即可。
服務(wù)端實(shí)現(xiàn)
** * @author:triumphxx * @Date:2021/11/12 * @Time:11:03 下午 * @微信公眾號(hào):北漂碼農(nóng)有話說 * @網(wǎng)站:http://blog.triumphxx.com.cn * @GitHub https://github.com/triumphxx * @Desc: NIO編程模型服務(wù)端 **/ public class NIOServer { // 通道管理器(Selector) private static Selector selector; public static void main(String[] args) throws IOException { // 創(chuàng)建通道管理器(Selector) selector = Selector.open(); // 創(chuàng)建通道ServerSocketChannel ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 將通道設(shè)置為非阻塞 serverSocketChannel.configureBlocking(false); // 將ServerSocketChannel對(duì)應(yīng)的ServerSocket綁定到指定端口(port) ServerSocket serverSocket = serverSocketChannel.socket(); serverSocket.bind(new InetSocketAddress(9090)); /** * 將通道(Channel)注冊(cè)到通道管理器(Selector),并為該通道注冊(cè)selectionKey.OP_ACCEPT事件 * 注冊(cè)該事件后,當(dāng)事件到達(dá)的時(shí)候,selector.select()會(huì)返回, * 如果事件沒有到達(dá)selector.select()會(huì)一直阻塞。 */ serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); // 循環(huán)處理 while (true) { // 當(dāng)注冊(cè)事件到達(dá)時(shí),方法返回,否則該方法會(huì)一直阻塞 selector.select(); // 獲取監(jiān)聽事件 Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = selectionKeys.iterator(); // 迭代處理 while (iterator.hasNext()) { // 獲取事件 SelectionKey key = iterator.next(); // 移除事件,避免重復(fù)處理 iterator.remove(); // 檢查是否是一個(gè)就緒的可以被接受的客戶端請(qǐng)求連接 if (key.isAcceptable()) { handleAccept(key); } else if (key.isReadable()) {// 檢查套接字是否已經(jīng)準(zhǔn)備好讀數(shù)據(jù) handleRead(key); } } } } /** * 處理客戶端連接成功事件 */ private static void handleAccept(SelectionKey key) throws IOException { // 獲取客戶端連接通道 ServerSocketChannel server = (ServerSocketChannel) key.channel(); SocketChannel socketChannel = server.accept(); socketChannel.configureBlocking(false); // 信息通過通道發(fā)送給客戶端 String msg = "Hello Client!"; socketChannel.write(ByteBuffer.wrap(msg.getBytes())); // 給通道設(shè)置讀事件,客戶端監(jiān)聽到讀事件后,進(jìn)行讀取操作 socketChannel.register(selector, SelectionKey.OP_READ); } /** * 監(jiān)聽到讀事件,讀取客戶端發(fā)送過來的消息 */ private static void handleRead(SelectionKey key) throws IOException { SocketChannel channel = (SocketChannel) key.channel(); // 從通道讀取數(shù)據(jù)到緩沖區(qū) ByteBuffer buffer = ByteBuffer.allocate(128); channel.read(buffer); // 輸出客戶端發(fā)送過來的消息 byte[] data = buffer.array(); String msg = new String(data).trim(); System.out.println("server received msg from client:" + msg); } }
有服務(wù)端的代碼可以知道:首先我們將 select 打開,然后創(chuàng)建通道、將通道設(shè)置為非阻塞、創(chuàng)建連接、完成注冊(cè) 等待監(jiān)聽、處理事件,詳細(xì)的每一行代碼的意思,都已經(jīng)進(jìn)展標(biāo)注。看代碼即可。
優(yōu)點(diǎn)及缺點(diǎn)
優(yōu)點(diǎn):可靠性高,吞吐量比較高、非阻塞
缺點(diǎn):編程模型做復(fù)雜
適用場(chǎng)景
適用于連接比較多且連接比較短的場(chǎng)景。
比如聊天室!
到此這篇關(guān)于Java中的同步非阻塞IO模型詳解的文章就介紹到這了,更多相關(guān)同步非阻塞IO模型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java基礎(chǔ)詳解之?dāng)?shù)據(jù)類型知識(shí)點(diǎn)總結(jié)
這篇文章主要介紹了java基礎(chǔ)詳解之?dāng)?shù)據(jù)類型知識(shí)點(diǎn)總結(jié),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很大的幫助,需要的朋友可以參考下2021-04-04java多態(tài)的向上轉(zhuǎn)型的概念及實(shí)例分析
在本篇內(nèi)容里小編給大家整理的是一篇關(guān)于java多態(tài)的向上轉(zhuǎn)型的概念及實(shí)例分析,對(duì)此有興趣的朋友們可以跟著學(xué)習(xí)下。2021-05-05elasticsearch中term與match的區(qū)別講解
今天小編就為大家分享一篇關(guān)于elasticsearch中term與match的區(qū)別講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-02-02elasticsearch節(jié)點(diǎn)間通信的基礎(chǔ)transport啟動(dòng)過程
這篇文章主要為大家介紹了elasticsearch節(jié)點(diǎn)間通信的基礎(chǔ)transport啟動(dòng)過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04關(guān)于Mybatis與JPA的優(yōu)缺點(diǎn)說明
這篇文章主要介紹了關(guān)于Mybatis與JPA的優(yōu)缺點(diǎn)說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06Java tomcat手動(dòng)配置servlet詳解
這篇文章主要為大家介紹了tomcat手動(dòng)配置servlet,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2021-11-11Spring?BeanFactory容器的構(gòu)建和使用示例詳解
BeanFactory是Spring框架中的一部分,它提供了IoC(控制反轉(zhuǎn))的實(shí)現(xiàn)機(jī)制,下面小編就來和大家簡(jiǎn)單聊聊BeanFactory容器的構(gòu)建和使用示例吧2023-07-07Spring中@Validated和@Valid區(qū)別淺析
@Valid是javax.validation里的,?@Validated是@Valid?的一次封裝,是Spring提供的校驗(yàn)機(jī)制使用,下面這篇文章主要給大家介紹了關(guān)于Spring中@Validated和@Valid區(qū)別的相關(guān)資料,需要的朋友可以參考下2022-04-04Java探索之Thread+IO文件的加密解密代碼實(shí)例
這篇文章主要介紹了Java探索之Thread+IO文件的加密解密代碼實(shí)例,具有一定參考價(jià)值,需要的朋友可以了解下。2017-10-10