Nginx_BIO_NIO_AIO面試題(2021最新版)

前言

在全部互聯網公司中,Nginx 做爲最經常使用的 7 層負載均衡代理層,每一個後端開發人員和運維人員都應該對其有較爲深刻的理解。java

小編分享的這份金三銀四Java後端開發面試總結包含了JavaOOP、Java集合容器、Java異常、併發編程、Java反射、Java序列化、JVM、Redis、Spring MVC、MyBatis、MySQL數據庫、消息中間件MQ、Dubbo、Linux、ZooKeeper、 分佈式&數據結構與算法等26個專題技術點,都是小編在各個大廠總結出來的面試真題,已經有不少粉絲靠這份PDF拿下衆多大廠的offer,今天在這裏總結分享給到你們!【持續更新中!】面試

完整版Java面試題地址:2021最新面試題合集集錦算法

序號 專題 內容 連接
1 中間件 Java中間件面試題(2021最新版) https://blog.51cto.com/14994509/2692669
2 微服務 Java微服務面試題(2021最新版) http://www.javashuo.com/article/p-haiifnkb-vk.html
3 併發編程 Java併發編程面試題(2021最新版) http://www.javashuo.com/article/p-rirekprn-vk.html
4 Java基礎 Java基礎知識面試題(2021最新版) https://blog.51cto.com/blogger/success/2706687
5 Spring Boot Spring Boot面試題(2021最新版) http://www.javashuo.com/article/p-etpzmprr-vk.html
6 Redis Redis面試題(2021最新版) http://www.javashuo.com/article/p-adjrmfwe-vk.html
7 Spring MVC Spring MVC面試題(2021最新版) https://blog.51cto.com/u_14994509/2711562
8 Spring Cloud Spring Cloud面試題(2021最新版) http://www.javashuo.com/article/p-emhafwrm-vk.html
9 MySQL優化 MySQL優化面試題(2021最新版) https://blog.51cto.com/u_14994509/2716504
10 JVM JVM性能調優面試題(2021最新版) https://blog.51cto.com/u_14994509/2716514
11 Linux Linux面試題(2021最新版) https://blog.51cto.com/u_14994509/2718559
12 Mybatis Mybatis面試題(2021最新版) https://blog.51cto.com/u_14994509/2718588
13 網絡編程 TCP,UDP,Socket,Http網絡編程面試題(2021最新版) https://blog.51cto.com/u_14994509/2718599
14 設計模式 設計模式面試題(2021最新版) https://blog.51cto.com/u_14994509/2735448
15 大數據 大數據面試題100道(2021最新版) https://blog.51cto.com/u_14994509/2736601
16 Tomcat Tomcat面試題(2021最新版) https://blog.51cto.com/u_14994509/2739386
17 多線程 多線程面試題(2021最新版) https://blog.51cto.com/u_14994509/2739435
18 Nginx Nginx_BIO_NIO_AIO面試題(2021最新版) 持續更新中!
19 memcache memcache面試題(2021最新版) 持續更新中!
20 java異常 java異常面試題(2021最新版) 持續更新中!
21 Java虛擬機 Java虛擬機面試題(2021最新版) 持續更新中!
22 Java集合 Java集合面試題(2021最新版) 持續更新中!
23 Git經常使用命令 Git經常使用命令(2021最新版) 持續更新中!
24 Elasticsearch Elasticsearch面試題(2021最新版) 持續更新中!
25 Dubbo Dubbo面試題(2021最新版) 持續更新中!

1. 什麼是IO

Nginx_BIO_NIO_AIO面試題(2021最新版)

2. 在瞭解不一樣的IO以前先了解:同步與異步,阻塞與非阻塞的區別

  • 同步,一個任務的完成以前不能作其餘操做,必須等待(等於在打電話)
  • 異步,一個任務的完成以前,能夠進行其餘操做(等於在聊QQ)
  • 阻塞,是相對於CPU來講的, 掛起當前線程,不能作其餘操做只能等待
  • 非阻塞,,無須掛起當前線程,能夠去執行其餘操做

3. 什麼是BIO

BIO:同步並阻塞,服務器實現一個鏈接一個線程,即客戶端有鏈接請求時服務器端就須要啓動一個線程進行處理,沒處理完以前此線程不能作其餘操做(若是是單線程的狀況下,我傳輸的文件很大呢?),固然能夠經過線程池機制改善。BIO方式適用於鏈接數目比較小且固定的架構,這種方式對服務器資源要求比較高,併發侷限於應用中,JDK1.4之前的惟一選擇,但程序直觀簡單易理解。數據庫

4. 什麼是NIO

NIO:同步非阻塞,服務器實現一個鏈接一個線程,即客戶端發送的鏈接請求都會註冊到多路複用器上,多路複用器輪詢到鏈接有I/O請求時才啓動一個線程進行處理。NIO方式適用於鏈接數目多且鏈接比較短(輕操做)的架構,好比聊天服務器,併發侷限於應用中,編程比較複雜,JDK1.4以後開始支持。 編程

5. 什麼是AIO

  • AIO:異步非阻塞,服務器實現模式爲一個有效請求一個線程,客戶端的I/O請求都是由操做系統先完成了再通知服務器應用去啓動線程進行處理,AIO方式使用於鏈接數目多且鏈接比較長(重操做)的架構,好比相冊服務器,充分調用操做系統參與併發操做,編程比較複雜,JDK1.7以後開始支持。.
  • AIO屬於NIO包中的類實現,其實IO主要分爲BIO和NIO,AIO只是附加品,解決IO不能異步的實現
  • 在之前不多有Linux系統支持AIO,Windows的IOCP就是該AIO模型。可是如今的服務器通常都是支持AIO操做

6. 什麼Netty

Nginx_BIO_NIO_AIO面試題(2021最新版)

7. BIO和NIO、AIO的區別

  • BIO是阻塞的,NIO是非阻塞的.
  • BIO是面向流的,只能單向讀寫,NIO是面向緩衝的, 能夠雙向讀寫
  • 使用BIO作Socket鏈接時,因爲單向讀寫,當沒有數據時,會掛起當前線程,阻塞等待,爲防止影響其它鏈接,,須要爲每一個鏈接新建線程處理.,然而系統資源是有限的,,不能過多的新建線程,線程過多帶來線程上下文的切換,歷來帶來更大的性能損耗,所以須要使用NIO進行BIO多路複用,使用一個線程來監聽全部Socket鏈接,使用本線程或者其餘線程處理鏈接
  • AIO是非阻塞 以異步方式發起 I/O 操做。當 I/O 操做進行時能夠去作其餘操做,由操做系統內核空間提醒IO操做已完成(不懂的能夠往下看)

8. IO流的分類

Nginx_BIO_NIO_AIO面試題(2021最新版)

9. 什麼是內核空間

Nginx_BIO_NIO_AIO面試題(2021最新版)

10. 五種IO模型

注意:我這裏的用戶空間就是應用程序空間 後端

10.1 阻塞BIO(blocking I/O)

image

10.2.非阻塞NIO(noblocking I/O)

B也在河邊釣魚,可是B不想將本身的全部時間都花費在釣魚上,在等魚上鉤這個時間段中,B也在作其餘的事情(一會看看書,一會讀讀報紙,一會又去看其餘人的釣魚等),但B在作這些事情的時候,每隔一個固定的時間檢查魚是否上鉤。一旦檢查到有魚上鉤,就停下手中的事情,把魚釣上來。 B在檢查魚竿是否有魚,是一個輪詢的過程。設計模式

Nginx_BIO_NIO_AIO面試題(2021最新版)

10.3.異步AIO(asynchronous I/O)

Nginx_BIO_NIO_AIO面試題(2021最新版)

10.4.信號驅動IO(signal blocking I/O)

G也在河邊釣魚,但與A、B、C不一樣的是,G比較聰明,他給魚竿上掛一個鈴鐺,當有魚上鉤的時候,這個鈴鐺就會被碰響,G就會將魚釣上來。 api

Nginx_BIO_NIO_AIO面試題(2021最新版)

10.5.IO多路轉接(I/O multiplexing)

Nginx_BIO_NIO_AIO面試題(2021最新版)

11. 什麼是比特(Bit),什麼是字節(Byte),什麼是字符(Char),它們長度是多少,各有什麼區別

  • Bit最小的二進制單位 ,是計算機的操做部分取值0或者1
  • Byte是計算機中存儲數據的單元,是一個8位的二進制數,(計算機內部,一個字節可表示一個英文字母,兩個字節可表示一個漢字。) 取值(-128-127)
  • Char是用戶的可讀寫的最小單位,他只是抽象意義上的一個符號。如‘5’,‘中’,‘¥’ 等等等等。在java裏面由16位bit組成Char 取值 (0-65535)
  • Bit 是最小單位 計算機他只能認識0或者1
  • Byte是8個字節 是給計算機看的
  • 字符 是看到的東西 一個字符=二個字節

12. 什麼叫對象序列化,什麼是反序列化,實現對象序列化須要作哪些工做

  • 對象序列化,將對象以二進制的形式保存在硬盤上
  • 反序列化;將二進制的文件轉化爲對象讀取
  • 實現serializable接口,不想讓字段放在硬盤上就加transient

13. 在實現序列化接口是時候通常要生成一個serialVersionUID字段,它叫作什麼,通常有什麼用

  • 若是用戶沒有本身聲明一個serialVersionUID,接口會默認生成一個serialVersionUID
  • 可是強烈建議用戶自定義一個serialVersionUID,由於默認的serialVersinUID對於class的細節很是敏感,反序列化時可能會致使InvalidClassException這個異常。
  • (好比說先進行序列化,而後在反序列化以前修改了類,那麼就會報錯。由於修改了類,對應的SerialversionUID也變化了,而序列化和反序列化就是經過對比其SerialversionUID來進行的,一旦SerialversionUID不匹配,反序列化就沒法成功。

14. 怎麼生成SerialversionUID

Nginx_BIO_NIO_AIO面試題(2021最新版)

15. BufferedReader屬於哪一種流,它主要是用來作什麼的,它裏面有那些經典的方法

屬於處理流中的緩衝流,能夠將讀取的內容存在內存裏面,有readLine()方法數組

16. Java中流類的超類主要有那些?

  • 超類表明頂端的父類(都是抽象類)
  • java.io.InputStream
  • java.io.OutputStream
  • java.io.Reader
  • java.io.Writer

17. 爲何圖片、視頻、音樂、文件等 都是要字節流來讀取

Nginx_BIO_NIO_AIO面試題(2021最新版)

18. IO的經常使用類和方法,以及如何使用

Nginx_BIO_NIO_AIO面試題(2021最新版)

19. IO基本操做講解

這裏的基本操做就是普通的讀取操做,若是想要跟深刻的瞭解不一樣的IO開發場景必須先了解IO的基本操做服務器

20. 網絡操做IO講解

  • 我這使用Socket簡單的來模擬網絡編程IO會帶來的問題
  • 不懂Socket能夠看我以前的文章,這個東西很容易懂的,就是基於TCP實現的網絡通訊,比http要快,不少實現網絡通訊的框架都是基於Socket來實現

21. 網絡操做IO編程演變歷史

21.1 BIO編程會出現什麼問題?

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

package com.test.io;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
//TCP協議Socket使用BIO進行通訊:服務端
public class BIOServer {
// 在main線程中執行下面這些代碼
public static void main(String[] args) {
//使用Socket進行網絡通訊
ServerSocket server = null;
Socket socket = null;
//基於字節流
InputStream in = null;
OutputStream out = null;
try {
server = new ServerSocket(8000);
System.out.println("服務端啓動成功,監聽端口爲8000,等待客戶端鏈接...");
while (true){
socket = server.accept(); //等待客戶端鏈接
System.out.println("客戶鏈接成功,客戶信息爲:" +
socket.getRemoteSocketAddress());
in = socket.getInputStream();
byte[] buffer = new byte[1024];
int len = 0;
//讀取客戶端的數據
while ((len = in.read(buffer)) > 0) {
System.out.println(new String(buffer, 0, len));
}
//向客戶端寫數據
out = socket.getOutputStream();
out.write("hello!".getBytes());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
TCP協議Socket使用BIO進行通訊:客戶端(第二執行)
package com.test.io;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
//TCP協議Socket使用BIO進行通訊:客戶端
public class Client01 {
public static void main(String[] args) throws IOException {
//建立套接字對象socket並封裝ip與port
Socket socket = new Socket("127.0.0.1", 8000);
//根據建立的socket對象得到一個輸出流
//基於字節流
OutputStream outputStream = socket.getOutputStream();
//控制檯輸入以IO的形式發送到服務器
System.out.println("TCP鏈接成功 \n請輸入:");
String str = new Scanner(System.in).nextLine();
byte[] car = str.getBytes();
outputStream.write(car);
System.out.println("TCP協議的Socket發送成功");
//刷新緩衝區
outputStream.flush();
//關閉鏈接
socket.close();
}
}
package com.test.io;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
//TCP協議Socket:客戶端
public class Client02 {
public static void main(String[] args) throws IOException {
//建立套接字對象socket並封裝ip與port
Socket socket = new Socket("127.0.0.1", 8000);
//根據建立的socket對象得到一個輸出流
//基於字節流
OutputStream outputStream = socket.getOutputStream();
//控制檯輸入以IO的形式發送到服務器
System.out.println("TCP鏈接成功 \n請輸入:");
String str = new Scanner(System.in).nextLine();
byte[] car = str.getBytes();
outputStream.write(car);
System.out.println("TCP協議的Socket發送成功");
//刷新緩衝區
outputStream.flush();
//關閉鏈接
socket.close();
}
}
  • 爲了解決堵塞問題,可使用多線程,請看下面

21.2 多線程解決BIO編程會出現的問題

這時有人就會說,我多線程不就解決了嗎?

  • 使用多線程是能夠解決堵塞等待時間很長的問題,由於他能夠充分發揮CPU
  • 然而系統資源是有限的,不能過多的新建線程,線程過多帶來線程上下文的切換,歷來帶來更大的性能損耗

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

package com.test.io;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
//TCP協議Socket使用多線程BIO進行通行:服務端
public class BIOThreadService {
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(8000);
System.out.println("服務端啓動成功,監聽端口爲8000,等待客戶端鏈接... ");
while (true) {
Socket socket = server.accept();//等待客戶鏈接
System.out.println("客戶鏈接成功,客戶信息爲:" +
socket.getRemoteSocketAddress());
//針對每一個鏈接建立一個線程, 去處理I0操做
//建立多線程建立開始
Thread thread = new Thread(new Runnable() {
public void run() {
try {
InputStream in = socket.getInputStream();
byte[] buffer = new byte[1024];
int len = 0;
//讀取客戶端的數據
while ((len = in.read(buffer)) > 0) {
System.out.println(new String(buffer, 0, len));
}
//向客戶端寫數據
OutputStream out = socket.getOutputStream();
out.write("hello".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
});
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
  • 爲了解決線程太多,這時又來了,線程池

21.3 線程池解決多線程BIO編程會出現的問題

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

package com.test.io;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//TCP協議Socket使用線程池BIO進行通行:服務端
public class BIOThreadPoolService {
    public static void main(String[] args) {
        //建立線程池
        ExecutorService executorService = Executors.newFixedThreadPool(30);
        try {
            ServerSocket server = new ServerSocket(8000);
            System.out.println("服務端啓動成功,監聽端口爲8000,等待客戶端鏈接...");
            while (true) {
                Socket socket = server.accept();
                //等待客戶鏈接
                System.out.println("客戶鏈接成功,客戶信息爲:" +
                socket.getRemoteSocketAddress());
                //使用線程池中的線程去執行每一個對應的任務
                executorService.execute(new Thread(new Runnable() {
                    public void run() {
                        try {
                            InputStream in = socket.getInputStream();
                            byte[] buffer = new byte[1024];
                            int len = 0;
                            //讀取客戶端的數據
                            while ((len = in.read(buffer)) > 0) {
                                System.out.println(new String(buffer, 0, len));
                            }
                            //向客戶端寫數據
                            OutputStream out = socket.getOutputStream();
                            out.write("hello".getBytes());
                        }
                        catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                )
                );
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

21.4 使用NIO實現網絡通訊

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

package com.test.io;
import com.lijie.iob.RequestHandler;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NIOServer {
    public static void main(String[] args) throws IOException {
        //111111111
        //Service端的Channel,監聽端口的
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        //設置爲非阻塞
        serverChannel.configureBlocking(false);
        //nio的api規定這樣賦值端口
        serverChannel.bind(new InetSocketAddress(8000));
        //顯示Channel是否已經啓動成功,包括綁定在哪一個地址上
        System.out.println("服務端啓動成功,監聽端口爲8000,等待客戶端鏈接..."+
        serverChannel.getLocalAddress());
        //22222222
        //聲明selector選擇器
        Selector selector = Selector.open();
        //這句話的含義,是把selector註冊到Channel上面,
        //每一個客戶端來了以後,就把客戶端註冊到Selector選擇器上,默認狀態是Accepted
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        //33333333
        //建立buffer緩衝區,聲明大小是1024,底層使用數組來實現的
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        RequestHandler requestHandler = new RequestHandler();
        //444444444
        //輪詢,服務端不斷輪詢,等待客戶端的鏈接
        //若是有客戶端輪詢上來就取出對應的Channel,沒有就一直輪詢
        while (true) {
            int select = selector.select();
            if (select == 0) {
                continue;
            }
            //有可能有不少,使用Set保存Channel
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                //使用SelectionKey來獲取鏈接了客戶端和服務端的Channel
                SelectionKey key = iterator.next();
                //判斷SelectionKey中的Channel狀態如何,若是是OP_ACCEPT就進入
                if (key.isAcceptable()) {
                    //從判斷SelectionKey中取出Channel
                    ServerSocketChannel channel = (ServerSocketChannel)
                    key.channel();
                    //拿到對應客戶端的Channel
                    SocketChannel clientChannel = channel.accept();
                    //把客戶端的Channel打印出來
                    System.out.println("客戶端通道信息打印:" + clientChannel.getRemoteAddress());
                    //設置客戶端的Channel設置爲非阻塞
                    clientChannel.configureBlocking(false);
                    //操做完了改變SelectionKey中的Channel的狀態OP_READ
                    clientChannel.register(selector, SelectionKey.OP_READ);
                }
                //到此輪訓到的時候,發現狀態是read,開始進行數據交互
                if (key.isReadable()) {
                    //以buffer做爲數據橋樑
                    SocketChannel channel = (SocketChannel) key.channel();
                    //數據要想讀要先寫,必須先讀取到buffer裏面進行操做
                    channel.read(buffer);
                    //進行讀取
                    String request = new String(buffer.array()).trim();
                    buffer.clear();
                    //進行打印buffer中的數據
                    System.out.println(String.format("客戶端發來的消息: %s : %s",
                    channel.getRemoteAddress(), request));
                    //要返回數據的話也要先返回buffer裏面進行返回
                    String response = requestHandler.handle(request);
                    //而後返回出去
                    channel.write(ByteBuffer.wrap(response.getBytes()));
                }
                iterator.remove();
            }
        }
    }
}

image

package com.test.io;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
//TCP協議Socket:客戶端
public class Client01 {
    public static void main(String[] args) throws IOException {
        //建立套接字對象socket並封裝ip與port
        Socket socket = new Socket("127.0.0.1", 8000);
        //根據建立的socket對象得到一個輸出流
        OutputStream outputStream = socket.getOutputStream();
        //控制檯輸入以IO的形式發送到服務器
        System.out.println("TCP鏈接成功 n請輸入:");
        while(true){
            byte[] car = new Scanner(System.in).nextLine().getBytes();
            outputStream.write(car);
            System.out.println("TCP協議的Socket發送成功");
            //刷新緩衝區
            outputStream.flush();
        }
    }
}

21.5 使用Netty實現網絡通訊

  • Netty是由JBOSS提供的一個Java開源框架。Netty提供異步的、事件驅動的網絡應用程序框架和工具,用以快速開發高性能、高可靠性的網絡服務器和客戶端程序。
  • Netty 是一個基於NIO的客戶、服務器端編程框架,使用Netty 能夠確保你快速和簡單的開發出一個網絡應用,例如實現了某種協議的客戶,服務端應用。Netty至關簡化和流線化了網絡應用的編程開發過程,例如,TCP和UDP的Socket服務開發。

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

Nginx_BIO_NIO_AIO面試題(2021最新版)

相關文章
相關標籤/搜索