這篇文章主要講解了“Java非阻塞IO和異步IO的詳細介紹”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Java非阻塞IO和異步IO的詳細介紹”吧!
網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)建站!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、成都小程序開發(fā)、集團企業(yè)網(wǎng)站建設(shè)等服務(wù)項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了東源免費建站歡迎大家使用!
我們已經(jīng)介紹過使用 Java NIO 包組成一個簡單的客戶端-服務(wù)端網(wǎng)絡(luò)通訊所需要的 ServerSocketChannel、SocketChannel 和 Buffer,我們這里整合一下它們,給出一個完整的可運行的例子:
public class Server { public static void main(String[] args) throws IOException { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 監(jiān)聽 8080 端口進來的 TCP 鏈接 serverSocketChannel.socket().bind(new InetSocketAddress(8080)); while (true) { // 這里會阻塞,直到有一個請求的連接進來 SocketChannel socketChannel = serverSocketChannel.accept(); // 開啟一個新的線程來處理這個請求,然后在 while 循環(huán)中繼續(xù)監(jiān)聽 8080 端口 SocketHandler handler = new SocketHandler(socketChannel); new Thread(handler).start(); } } }
這里看一下新的線程需要做什么,SocketHandler:
public class SocketHandler implements Runnable { private SocketChannel socketChannel; public SocketHandler(SocketChannel socketChannel) { this.socketChannel = socketChannel; } @Override public void run() { ByteBuffer buffer = ByteBuffer.allocate(1024); try { // 將請求數(shù)據(jù)讀入 Buffer 中 int num; while ((num = socketChannel.read(buffer)) > 0) { // 讀取 Buffer 內(nèi)容之前先 flip 一下 buffer.flip(); // 提取 Buffer 中的數(shù)據(jù) byte[] bytes = new byte[num]; buffer.get(bytes); String re = new String(bytes, "UTF-8"); System.out.println("收到請求:" + re); // 回應(yīng)客戶端 ByteBuffer writeBuffer = ByteBuffer.wrap(("我已經(jīng)收到你的請求,你的請求內(nèi)容是:" + re).getBytes()); socketChannel.write(writeBuffer); buffer.clear(); } } catch (IOException e) { IOUtils.closeQuietly(socketChannel); } } }
最后,貼一下客戶端 SocketChannel 的使用,客戶端比較簡單:
public class SocketChannelTest { public static void main(String[] args) throws IOException { SocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress("localhost", 8080)); // 發(fā)送請求 ByteBuffer buffer = ByteBuffer.wrap("1234567890".getBytes()); socketChannel.write(buffer); // 讀取響應(yīng) ByteBuffer readBuffer = ByteBuffer.allocate(1024); int num; if ((num = socketChannel.read(readBuffer)) > 0) { readBuffer.flip(); byte[] re = new byte[num]; readBuffer.get(re); String result = new String(re, "UTF-8"); System.out.println("返回值: " + result); } } }
上面介紹的阻塞模式的代碼應(yīng)該很好理解:來一個新的連接,我們就新開一個線程來處理這個連接,之后的操作全部由那個線程來完成。
那么,這個模式下的性能瓶頸在哪里呢?
首先,每次來一個連接都開一個新的線程這肯定是不合適的。當(dāng)活躍連接數(shù)在幾十幾百的時候當(dāng)然是可以這樣做的,但如果活躍連接數(shù)是幾萬幾十萬的時候,這么多線程明顯就不行了。每個線程都需要一部分內(nèi)存,內(nèi)存會被迅速消耗,同時,線程切換的開銷非常大。
其次,阻塞操作在這里也是一個問題。首先,accept() 是一個阻塞操作,當(dāng) accept() 返回的時候,代表有一個連接可以使用了,我們這里是馬上就新建線程來處理這個 SocketChannel 了,但是,但是這里不代表對方就將數(shù)據(jù)傳輸過來了。所以,SocketChannel#read 方法將阻塞,等待數(shù)據(jù),明顯這個等待是不值得的。同理,write 方法也需要等待通道可寫才能執(zhí)行寫入操作,這邊的阻塞等待也是不值得的。
說完了阻塞模式的使用及其缺點以后,我們這里就可以介紹非阻塞 IO 了。
非阻塞 IO 的核心在于使用一個 Selector 來管理多個通道,可以是 SocketChannel,也可以是 ServerSocketChannel,將各個通道注冊到 Selector 上,指定監(jiān)聽的事件。
之后可以只用一個線程來輪詢這個 Selector,看看上面是否有通道是準備好的,當(dāng)通道準備好可讀或可寫,然后才去開始真正的讀寫,這樣速度就很快了。我們就完全沒有必要給每個通道都起一個線程。
NIO 中 Selector 是對底層操作系統(tǒng)實現(xiàn)的一個抽象,管理通道狀態(tài)其實都是底層系統(tǒng)實現(xiàn)的,這里簡單介紹下在不同系統(tǒng)下的實現(xiàn)。
select:上世紀 80 年代就實現(xiàn)了,它支持注冊 FD_SETSIZE(1024) 個 socket,在那個年代肯定是夠用的,不過現(xiàn)在嘛,肯定是不行了。
poll:1997 年,出現(xiàn)了 poll 作為 select 的替代者,最大的區(qū)別就是,poll 不再限制 socket 數(shù)量。
select 和 poll 都有一個共同的問題,那就是它們都只會告訴你有幾個通道準備好了,但是不會告訴你具體是哪幾個通道。所以,一旦知道有通道準備好以后,自己還是需要進行一次掃描,顯然這個不太好,通道少的時候還行,一旦通道的數(shù)量是幾十萬個以上的時候,掃描一次的時間都很可觀了,時間復(fù)雜度 O(n)。所以,后來才催生了以下實現(xiàn)。
epoll:2002 年隨 Linux 內(nèi)核 2.5.44 發(fā)布,epoll 能直接返回具體的準備好的通道,時間復(fù)雜度 O(1)。
除了 Linux 中的 epoll,2000 年 FreeBSD 出現(xiàn)了 Kqueue,還有就是,Solaris 中有 /dev/poll。
前面說了那么多實現(xiàn),但是沒有出現(xiàn) Windows,Windows 平臺的非阻塞 IO 使用 select,我們也不必覺得 Windows 很落后,在 Windows 中 IOCP 提供的異步 IO 是比較強大的。
我們回到 Selector,畢竟 JVM 就是這么一個屏蔽底層實現(xiàn)的平臺,我們面向 Selector 編程就可以了。
之前在介紹 Selector 的時候已經(jīng)了解過了它的基本用法,這邊來一個可運行的實例代碼,大家不妨看看:
public class SelectorServer { public static void main(String[] args) throws IOException { Selector selector = Selector.open(); ServerSocketChannel server = ServerSocketChannel.open(); server.socket().bind(new InetSocketAddress(8080)); // 將其注冊到 Selector 中,監(jiān)聽 OP_ACCEPT 事件 server.configureBlocking(false); server.register(selector, SelectionKey.OP_ACCEPT); while (true) { int readyChannels = selector.select(); if (readyChannels == 0) { continue; } SetreadyKeys = selector.selectedKeys(); // 遍歷 Iterator iterator = readyKeys.iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); if (key.isAcceptable()) { // 有已經(jīng)接受的新的到服務(wù)端的連接 SocketChannel socketChannel = server.accept(); // 有新的連接并不代表這個通道就有數(shù)據(jù), // 這里將這個新的 SocketChannel 注冊到 Selector,監(jiān)聽 OP_READ 事件,等待數(shù)據(jù) socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { // 有數(shù)據(jù)可讀 // 上面一個 if 分支中注冊了監(jiān)聽 OP_READ 事件的 SocketChannel SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer readBuffer = ByteBuffer.allocate(1024); int num = socketChannel.read(readBuffer); if (num > 0) { // 處理進來的數(shù)據(jù)... System.out.println("收到數(shù)據(jù):" + new String(readBuffer.array()).trim()); ByteBuffer buffer = ByteBuffer.wrap("返回給客戶端的數(shù)據(jù)...".getBytes()); socketChannel.write(buffer); } else if (num == -1) { // -1 代表連接已經(jīng)關(guān)閉 socketChannel.close(); } } } } } }
至于客戶端,大家可以繼續(xù)使用上一節(jié)介紹阻塞模式時的客戶端進行測試。
More New IO,或稱 NIO.2,隨 JDK 1.7 發(fā)布,包括了引入異步 IO 接口和 Paths 等文件訪問接口。
異步這個詞,我想對于絕大多數(shù)開發(fā)者來說都很熟悉,很多場景下我們都會使用異步。
通常,我們會有一個線程池用于執(zhí)行異步任務(wù),提交任務(wù)的線程將任務(wù)提交到線程池就可以立馬返回,不必等到任務(wù)真正完成。如果想要知道任務(wù)的執(zhí)行結(jié)果,通常是通過傳遞一個回調(diào)函數(shù)的方式,任務(wù)結(jié)束后去調(diào)用這個函數(shù)。
同樣的原理,Java 中的異步 IO 也是一樣的,都是由一個線程池來負責(zé)執(zhí)行任務(wù),然后使用回調(diào)或自己去查詢結(jié)果。
大部分開發(fā)者都知道為什么要這么設(shè)計了,這里再啰嗦一下。異步 IO 主要是為了控制線程數(shù)量,減少過多的線程帶來的內(nèi)存消耗和 CPU 在線程調(diào)度上的開銷。
在 Unix/Linux 等系統(tǒng)中,JDK 使用了并發(fā)包中的線程池來管理任務(wù),具體可以查看 AsynchronousChannelGroup 的源碼。
在 Windows 操作系統(tǒng)中,提供了一個叫做 I/O Completion Ports 的方案,通常簡稱為 IOCP,操作系統(tǒng)負責(zé)管理線程池,其性能非常優(yōu)異,所以在 Windows 中 JDK 直接采用了 IOCP 的支持,使用系統(tǒng)支持,把更多的操作信息暴露給操作系統(tǒng),也使得操作系統(tǒng)能夠?qū)ξ覀兊?IO 進行一定程度的優(yōu)化。
在 Linux 中其實也是有異步 IO 系統(tǒng)實現(xiàn)的,但是限制比較多,性能也一般,所以 JDK 采用了自建線程池的方式。
本文還是以實用為主,想要了解更多信息請自行查找其他資料,下面對 Java 異步 IO 進行實踐性的介紹。
總共有三個類需要我們關(guān)注,分別是 AsynchronousSocketChannel,AsynchronousServerSocketChannel和 AsynchronousFileChannel,只不過是在之前介紹的 FileChannel、SocketChannel 和 ServerSocketChannel 的類名上加了個前綴 Asynchronous。
Java 異步 IO 提供了兩種使用方式,分別是返回 Future 實例和使用回調(diào)函數(shù)。
返回 java.util.concurrent.Future 實例的方式我們應(yīng)該很熟悉,JDK 線程池就是這么使用的。Future 接口的幾個方法語義在這里也是通用的,這里先做簡單介紹。
future.isDone();
判斷操作是否已經(jīng)完成,包括了正常完成、異常拋出、取消
future.cancel(true);
取消操作,方式是中斷。參數(shù) true 說的是,即使這個任務(wù)正在執(zhí)行,也會進行中斷。
future.isCancelled();
是否被取消,只有在任務(wù)正常結(jié)束之前被取消,這個方法才會返回 true
future.get();
這是我們的老朋友,獲取執(zhí)行結(jié)果,阻塞。
future.get(10, TimeUnit.SECONDS);
如果上面的 get() 方法的阻塞你不滿意,那就設(shè)置個超時時間。
java.nio.channels.CompletionHandler 接口定義:
public interface CompletionHandler{ void completed(V result, A attachment); void failed(Throwable exc, A attachment); }
注意,參數(shù)上有個 attachment,雖然不常用,我們可以在各個支持的方法中傳遞這個參數(shù)值
AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel.open().bind(null); // accept 方法的第一個參數(shù)可以傳遞 attachment listener.accept(attachment, new CompletionHandler() { public void completed( AsynchronousSocketChannel client, Object attachment) { // } public void failed(Throwable exc, Object attachment) { // } });
網(wǎng)上關(guān)于 Non-Blocking IO 的介紹文章很多,但是 Asynchronous IO 的文章相對就少得多了,所以我這邊會多介紹一些相關(guān)內(nèi)容。
首先,我們就來關(guān)注異步的文件 IO,前面我們說了,文件 IO 在所有的操作系統(tǒng)中都不支持非阻塞模式,但是我們可以對文件 IO 采用異步的方式來提高性能。
下面,我會介紹 AsynchronousFileChannel 里面的一些重要的接口,都很簡單,讀者要是覺得無趣,直接滑到下一個標(biāo)題就可以了。
實例化:
AsynchronousFileChannel channel = AsynchronousFileChannel.open(Paths.get("/Users/hongjie/test.txt"));
一旦實例化完成,我們就可以著手準備將數(shù)據(jù)讀入到 Buffer 中:
ByteBuffer buffer = ByteBuffer.allocate(1024); Futureresult = channel.read(buffer, 0);
異步文件通道的讀操作和寫操作都需要提供一個文件的開始位置,文件開始位置為 0
除了使用返回 Future 實例的方式,也可以采用回調(diào)函數(shù)進行操作,接口如下:
public abstract void read(ByteBuffer dst, long position, A attachment, CompletionHandlerhandler);
順便也貼一下寫操作的兩個版本的接口:
public abstract Futurewrite(ByteBuffer src, long position); public abstract void write(ByteBuffer src, long position, A attachment, CompletionHandler handler);
我們可以看到,AIO 的讀寫主要也還是與 Buffer 打交道,這個與 NIO 是一脈相承的。
另外,還提供了用于將內(nèi)存中的數(shù)據(jù)刷入到磁盤的方法:
public abstract void force(boolean metaData) throws IOException;
因為我們對文件的寫操作,操作系統(tǒng)并不會直接針對文件操作,系統(tǒng)會緩存,然后周期性地刷入到磁盤。如果希望將數(shù)據(jù)及時寫入到磁盤中,以免斷電引發(fā)部分數(shù)據(jù)丟失,可以調(diào)用此方法。參數(shù)如果設(shè)置為 true,意味著同時也將文件屬性信息更新到磁盤。
還有,還提供了對文件的鎖定功能,我們可以鎖定文件的部分數(shù)據(jù),這樣可以進行排他性的操作。
public abstract Futurelock(long position, long size, boolean shared);
position 是要鎖定內(nèi)容的開始位置,size 指示了要鎖定的區(qū)域大小,shared 指示需要的是共享鎖還是排他鎖
當(dāng)然,也可以使用回調(diào)函數(shù)的版本:
public abstract void lock(long position, long size, boolean shared, A attachment, CompletionHandlerhandler);
文件鎖定功能上還提供了 tryLock 方法,此方法會快速返回結(jié)果:
public abstract FileLock tryLock(long position, long size, boolean shared) throws IOException;
這個方法很簡單,就是嘗試去獲取鎖,如果該區(qū)域已被其他線程或其他應(yīng)用鎖住,那么立刻返回 null,否則返回 FileLock 對象。
AsynchronousFileChannel 操作大體上也就以上介紹的這些接口,還是比較簡單的,這里就少一些廢話早點結(jié)束好了。
這個類對應(yīng)的是非阻塞 IO 的 ServerSocketChannel,大家可以類比下使用方式。
我們就廢話少說,用代碼說事吧:
package com.javadoop.aio; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; public class Server { public static void main(String[] args) throws IOException { // 實例化,并監(jiān)聽端口 AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(8080)); // 自己定義一個 Attachment 類,用于傳遞一些信息 Attachment att = new Attachment(); att.setServer(server); server.accept(att, new CompletionHandler() { @Override public void completed(AsynchronousSocketChannel client, Attachment att) { try { SocketAddress clientAddr = client.getRemoteAddress(); System.out.println("收到新的連接:" + clientAddr); // 收到新的連接后,server 應(yīng)該重新調(diào)用 accept 方法等待新的連接進來 att.getServer().accept(att, this); Attachment newAtt = new Attachment(); newAtt.setServer(server); newAtt.setClient(client); newAtt.setReadMode(true); newAtt.setBuffer(ByteBuffer.allocate(2048)); // 這里也可以繼續(xù)使用匿名實現(xiàn)類,不過代碼不好看,所以這里專門定義一個類 client.read(newAtt.getBuffer(), newAtt, new ChannelHandler()); } catch (IOException ex) { ex.printStackTrace(); } } @Override public void failed(Throwable t, Attachment att) { System.out.println("accept failed"); } }); // 為了防止 main 線程退出 try { Thread.currentThread().join(); } catch (InterruptedException e) { } } }
看一下 ChannelHandler 類:
package com.javadoop.aio; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.CompletionHandler; import java.nio.charset.Charset; public class ChannelHandler implements CompletionHandler{ @Override public void completed(Integer result, Attachment att) { if (att.isReadMode()) { // 讀取來自客戶端的數(shù)據(jù) ByteBuffer buffer = att.getBuffer(); buffer.flip(); byte bytes[] = new byte[buffer.limit()]; buffer.get(bytes); String msg = new String(buffer.array()).toString().trim(); System.out.println("收到來自客戶端的數(shù)據(jù): " + msg); // 響應(yīng)客戶端請求,返回數(shù)據(jù) buffer.clear(); buffer.put("Response from server!".getBytes(Charset.forName("UTF-8"))); att.setReadMode(false); buffer.flip(); // 寫數(shù)據(jù)到客戶端也是異步 att.getClient().write(buffer, att, this); } else { // 到這里,說明往客戶端寫數(shù)據(jù)也結(jié)束了,有以下兩種選擇: // 1\. 繼續(xù)等待客戶端發(fā)送新的數(shù)據(jù)過來 // att.setReadMode(true); // att.getBuffer().clear(); // att.getClient().read(att.getBuffer(), att, this); // 2\. 既然服務(wù)端已經(jīng)返回數(shù)據(jù)給客戶端,斷開這次的連接 try { att.getClient().close(); } catch (IOException e) { } } } @Override public void failed(Throwable t, Attachment att) { System.out.println("連接斷開"); } }
順便再貼一下自定義的 Attachment 類:
public class Attachment { private AsynchronousServerSocketChannel server; private AsynchronousSocketChannel client; private boolean isReadMode; private ByteBuffer buffer; // getter & setter }
這樣,一個簡單的服務(wù)端就寫好了,接下來可以接收客戶端請求了。上面我們用的都是回調(diào)函數(shù)的方式,讀者要是感興趣,可以試試寫個使用 Future 的。
其實,說完上面的 AsynchronousServerSocketChannel,基本上讀者也就知道怎么使用 AsynchronousSocketChannel 了,和非阻塞 IO 基本類似。
這邊做個簡單演示,這樣讀者就可以配合之前介紹的 Server 進行測試使用了。
package com.javadoop.aio; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.charset.Charset; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; public class Client { public static void main(String[] args) throws Exception { AsynchronousSocketChannel client = AsynchronousSocketChannel.open(); // 來個 Future 形式的 Future> future = client.connect(new InetSocketAddress(8080)); // 阻塞一下,等待連接成功 future.get(); Attachment att = new Attachment(); att.setClient(client); att.setReadMode(false); att.setBuffer(ByteBuffer.allocate(2048)); byte[] data = "I am obot!".getBytes(); att.getBuffer().put(data); att.getBuffer().flip(); // 異步發(fā)送數(shù)據(jù)到服務(wù)端 client.write(att.getBuffer(), att, new ClientChannelHandler()); // 這里休息一下再退出,給出足夠的時間處理數(shù)據(jù) Thread.sleep(2000); } }
往里面看下 ClientChannelHandler 類:
package com.javadoop.aio; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.CompletionHandler; import java.nio.charset.Charset; public class ClientChannelHandler implements CompletionHandler{ @Override public void completed(Integer result, Attachment att) { ByteBuffer buffer = att.getBuffer(); if (att.isReadMode()) { // 讀取來自服務(wù)端的數(shù)據(jù) buffer.flip(); byte[] bytes = new byte[buffer.limit()]; buffer.get(bytes); String msg = new String(bytes, Charset.forName("UTF-8")); System.out.println("收到來自服務(wù)端的響應(yīng)數(shù)據(jù): " + msg); // 接下來,有以下兩種選擇: // 1\. 向服務(wù)端發(fā)送新的數(shù)據(jù) // att.setReadMode(false); // buffer.clear(); // String newMsg = "new message from client"; // byte[] data = newMsg.getBytes(Charset.forName("UTF-8")); // buffer.put(data); // buffer.flip(); // att.getClient().write(buffer, att, this); // 2\. 關(guān)閉連接 try { att.getClient().close(); } catch (IOException e) { } } else { // 寫操作完成后,會進到這里 att.setReadMode(true); buffer.clear(); att.getClient().read(buffer, att, this); } } @Override public void failed(Throwable t, Attachment att) { System.out.println(" 以上代碼都是可以運行調(diào)試的,如果讀者碰到問題,請在評論區(qū)留言。
Asynchronous Channel Groups
為了知識的完整性,有必要對 group 進行介紹,其實也就是介紹 AsynchronousChannelGroup 這個類。之前我們說過,異步 IO 一定存在一個線程池,這個線程池負責(zé)接收任務(wù)、處理 IO 事件、回調(diào)等。這個線程池就在 group 內(nèi)部,group 一旦關(guān)閉,那么相應(yīng)的線程池就會關(guān)閉。
AsynchronousServerSocketChannels 和 AsynchronousSocketChannels 是屬于 group 的,當(dāng)我們調(diào)用 AsynchronousServerSocketChannel 或 AsynchronousSocketChannel 的 open() 方法的時候,相應(yīng)的 channel 就屬于默認的 group,這個 group 由 JVM 自動構(gòu)造并管理。
如果我們想要配置這個默認的 group,可以在 JVM 啟動參數(shù)中指定以下系統(tǒng)變量:
java.nio.channels.DefaultThreadPool.threadFactory
此系統(tǒng)變量用于設(shè)置 ThreadFactory,它應(yīng)該是 java.util.concurrent.ThreadFactory 實現(xiàn)類的全限定類名。一旦我們指定了這個 ThreadFactory 以后,group 中的線程就會使用該類產(chǎn)生。
java.nio.channels.DefaultThreadPool.initialSize
此系統(tǒng)變量也很好理解,用于設(shè)置線程池的初始大小。
可能你會想要使用自己定義的 group,這樣可以對其中的線程進行更多的控制,使用以下幾個方法即可:
AsynchronousChannelGroup.withCachedThreadPool(ExecutorService executor, int initialSize)
AsynchronousChannelGroup.withFixedThreadPool(int nThreads, ThreadFactory threadFactory)
AsynchronousChannelGroup.withThreadPool(ExecutorService executor)
熟悉線程池的讀者對這些方法應(yīng)該很好理解,它們都是 AsynchronousChannelGroup 中的靜態(tài)方法。
至于 group 的使用就很簡單了,代碼一看就懂:
AsynchronousChannelGroup group = AsynchronousChannelGroup .withFixedThreadPool(10, Executors.defaultThreadFactory()); AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open(group); AsynchronousSocketChannel client = AsynchronousSocketChannel.open(group);AsynchronousFileChannels 不屬于 group。但是它們也是關(guān)聯(lián)到一個線程池的,如果不指定,會使用系統(tǒng)默認的線程池,如果想要使用指定的線程池,可以在實例化的時候使用以下方法:
public static AsynchronousFileChannel open(Path file, Set extends OpenOption> options, ExecutorService executor, FileAttribute>... attrs) { ... }到這里,異步 IO 就算介紹完成了。
感謝各位的閱讀,以上就是“Java非阻塞IO和異步IO的詳細介紹”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Java非阻塞IO和異步IO的詳細介紹這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!
本文題目:Java非阻塞IO和異步IO的詳細介紹
鏈接地址:http://weahome.cn/article/gcjees.html