阿里面试题BIO和NIO数量问题附答案和代码
生活随笔
收集整理的這篇文章主要介紹了
阿里面试题BIO和NIO数量问题附答案和代码
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、問題
BIO 和 NIO 作為 Server 端,當建立了 10 個連接時,分別產生多少個線程?
答案: 因為傳統的 IO 也就是 BIO 是同步線程堵塞的,所以每個連接都要分配一個專用線程來處理請求,這樣 10 個連接就會創建 10 個線程去處理。而 NIO 是一種同步非阻塞的 I/O 模型,它的核心技術是多路復用,可以使用一個鏈接上的不同通道來處理不同的請求,所以即使有 10 個連接,對于 NIO 來說,開啟 1 個線程就夠了。
二、BIO 代碼實現
public class DemoServer extends Thread {private ServerSocket serverSocket;public int getPort() {return serverSocket.getLocalPort();}public void run() {try {serverSocket = new ServerSocket(0);while (true) {Socket socket = serverSocket.accept();RequestHandler requestHandler = new RequestHandler(socket);requestHandler.start();}} catch (IOException e) {e.printStackTrace();} finally {if (serverSocket != null) {try {serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}}public static void main(String[] args) throws IOException {DemoServer server = new DemoServer();server.start();try (Socket client = new Socket(InetAddress.getLocalHost(), server.getPort())) {BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));bufferedReader.lines().forEach(s -> System.out.println(s));}}} // 簡化實現,不做讀取,直接發送字符串 class RequestHandler extends Thread {private Socket socket;RequestHandler(Socket socket) {this.socket = socket;}@Overridepublic void run() {try (PrintWriter out = new PrintWriter(socket.getOutputStream());) {out.println("Hello world!");out.flush();} catch (Exception e) {e.printStackTrace();}}}- 服務器端啟動 ServerSocket,端口 0 表示自動綁定一個空閑端口。
- 調用 accept 方法,阻塞等待客戶端連接。
- 利用 Socket 模擬了一個簡單的客戶端,只進行連接、讀取、打印。
- 當連接建立后,啟動一個單獨線程負責回復客戶端請求。
這樣,一個簡單的 Socket 服務器就被實現出來了。
(圖片來源于楊曉峰)
三、NIO 代碼實現
public class NIOServer extends Thread {public void run() {try (Selector selector = Selector.open();ServerSocketChannel serverSocket = ServerSocketChannel.open();) {// 創建 Selector 和 ChannelserverSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 8888));serverSocket.configureBlocking(false);// 注冊到 Selector,并說明關注點serverSocket.register(selector, SelectionKey.OP_ACCEPT);while (true) {selector.select();// 阻塞等待就緒的 Channel,這是關鍵點之一Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> iter = selectedKeys.iterator();while (iter.hasNext()) {SelectionKey key = iter.next();// 生產系統中一般會額外進行就緒狀態檢查sayHelloWorld((ServerSocketChannel) key.channel());iter.remove();}}} catch (IOException e) {e.printStackTrace();}}private void sayHelloWorld(ServerSocketChannel server) throws IOException {try (SocketChannel client = server.accept();) { client.write(Charset.defaultCharset().encode("Hello world!"));}}// 省略了與前面類似的 main }- 首先,通過 Selector.open() 創建一個 Selector,作為類似調度員的角色。
- 然后,創建一個 ServerSocketChannel,并且向 Selector 注冊,通過指定 SelectionKey.OP_ACCEPT,告訴調度員,它關注的是新的連接請求。注意:為什么我們要明確配置非阻塞模式呢?這是因為阻塞模式下,注冊操作是不允許的,會拋出 IllegalBlockingModeException 異常。
- Selector 阻塞在 select 操作,當有 Channel 發生接入請求,就會被喚醒。
- 在 sayHelloWorld 方法中,通過 SocketChannel 和 Buffer 進行數據操作,在本例中是發送了一段字符串。
可以看到,在前面兩個樣例中,IO 都是同步阻塞模式,所以需要多線程以實現多任務處理。而 NIO 則是利用了單線程輪詢事件的機制,通過高效地定位就緒的 Channel,來決定做什么,僅僅 select 階段是阻塞的,可以有效避免大量客戶端連接時,頻繁線程切換帶來的問題,應用的擴展能力有了非常大的提高。下面這張圖對這種實現思路進行了形象地說明。
(圖片來源于楊曉峰)
四、參考資料
Java核心36講
近期熱門文章
Java 最常見的 200+ 面試題
如果你喜歡本文,掃描二維碼關注微信公眾號「王磊的博客」
總結
以上是生活随笔為你收集整理的阿里面试题BIO和NIO数量问题附答案和代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个好的技术团队应该怎么选择开发语言
- 下一篇: 单线程的Redis为什么却能支撑高并发?