TP-LINK面試真題和答案,您能做對幾道?

話說 TP-LINK 聯洲的秋招提前批已經開啓很久了,6 月份就已經開啓了,並且最近已經有人陸陸續續拿到口頭 Offer 了,所以今天就來給大家介紹一下 TP-LINK 的面試流程和真題及答案解析。

秋招提前批投遞地址

官網投遞地址:https://hr.tp-link.com.cn/jobList

TP-LINK 整個面試流程如下:

  1. 技術面:兩面或者是三面,普通 Offer 兩面,SP Offer 三面。
  2. 心理評測
  3. 座談會
  4. 簽約
  5. 電話 OC
  6. 簽訂三方協議

面試問題

問題來源於某客,如下圖所示:
無標題.png

問題鏈接:https://www.nowcoder.com/feed/main/detail/9af7b7989419489284b3cfce7aaae2bc

答案解析

1.說一下微服務架構?

微服務是一種軟件開發架構風格,用於構建複雜應用程序。
image.png
它將大型應用程序拆分成一系列較小、獨立的服務,每個服務專注於完成特定的業務功能。這些服務之間通過輕量級的通信機制(通常是基於 HTTP 或 RPC)進行交互,可以獨立部署、擴展和管理。

微服務的主要特點包括:

  1. 單一責任:每個微服務專注於執行一個明確定義的業務功能。這使得開發人員可以更容易地理解和維護服務。
  2. 松耦合:微服務之間是獨立的,它們可以使用不同的編程語言、技術堆棧和數據存儲。這種松耦合使得開發團隊能夠獨立地開發、測試和部署各個服務。
  3. 獨立部署:每個微服務都可以獨立地部署,這意味着當對一個服務進行更改時,不需要重新部署整個應用程序。這提高了開發和發佈的速度,並允許快速迭代和靈活性。
  4. 彈性擴展:由於每個微服務是獨立的,可以根據需要對它們進行獨立的擴展。這使得應用程序能夠更好地處理高負載情況,並具有更好的可伸縮性。
  5. 有限上下文:每個微服務維護自己的數據存儲,這意味着它們可以使用不同類型的數據庫或存儲技術。這種隔離有助於減少整個系統的複雜性,並提高可靠性。

2.微服務優缺點

微服務架構具有以下優點:

  1. 松耦合:微服務架構使得各個服務之間的耦合度降低,每個服務都是獨立的,可以使用不同的編程語言、技術堆棧和數據存儲。這樣可以提高團隊的自治性,各個服務可以獨立開發、測試和部署。
  2. 可伸縮性:由於微服務是獨立的,可以根據需要對每個服務進行獨立的擴展。這意味着可以根據流量和負載的需求,對具體的服務進行水平擴展,提高系統的性能和可用性。
  3. 獨立部署:每個微服務都可以獨立地部署,這樣在更新或修復某個服務時,不需要重新部署整個應用程序。這樣可以降低風險,並提高開發和發佈的速度。
  4. 技術異構性:微服務架構允許不同的服務使用不同的技術和工具。這樣可以選擇最適合每個服務需求的技術,提高開發效率和靈活性。
  5. 易於理解和維護:微服務架構將複雜的應用程序拆分爲小而獨立的服務,每個服務專注於一個明確定義的業務功能。這樣使得代碼庫更易於理解和維護。

然而,微服務架構也存在一些挑戰和缺點:

  1. 分佈式系統複雜性:微服務架構中的服務是分佈式的,需要處理服務間通信、數據一致性、錯誤處理等問題。這增加了系統的複雜性,需要更多的設計和管理工作。
  2. 服務間通信開銷:由於微服務架構中的服務通過網絡通信進行交互,會增加一定的延遲和開銷。此外,需要實現適當的通信機制和協議來確保可靠性和數據一致性。
  3. 運維複雜性:微服務架構中涉及多個獨立的服務,每個服務都需要獨立進行監控、日誌記錄和故障排除。這增加了運維的複雜性,需要適當的工具和自動化來管理和監控服務。
  4. 數據一致性:由於每個微服務維護自己的數據存儲,確保數據一致性變得更加困難。在跨多個服務的業務操作中,需要採取適當的策略和技術來保證數據的一致性和完整性。

3.負載均衡的實現算法

負載均衡是指將網絡流量或工作負載分配到多個服務器或計算資源上,以提高系統的性能、可靠性和可擴展性。在實現負載均衡時,通常會採用以下算法:

  1. 輪詢(Round Robin):按照輪詢的方式依次將請求分發給後端服務器。每個請求按照順序依次分配給不同的服務器,循環往復。這種算法簡單且均衡,適用於服務器性能相似且無狀態的情況。
  2. 最少連接(Least Connection):根據當前連接數選擇連接數最少的服務器來處理新的請求。這種算法可以有效地將負載均衡到連接數較少的服務器上,以保持各服務器的負載相對均衡。
  3. IP哈希(IP Hash):根據客戶端的 IP 地址進行哈希計算,將同一個 IP 地址的請求發送到同一個後端服務器。這樣可以確保同一個客戶端的請求都發送到同一臺服務器上,適用於需要保持會話一致性的場景。
  4. 加權輪詢(Weighted Round Robin):給每個服務器分配一個權重值,根據權重值的比例來分配請求。具有較高權重的服務器會接收到更多的請求,適用於服務器性能不均衡的情況。
  5. 加權最少連接(Weighted Least Connection):根據服務器的當前連接數和權重值來選擇服務器。連接數越少且權重值越高的服務器會被優先選擇。
  6. 隨機(Random):隨機選擇一個後端服務器來處理請求。這種算法簡單且均衡,但無法保證每個服務器的負載一致。
  7. 響應時間加權(Response Time Weighted):根據服務器的平均響應時間或處理時間來分配請求。響應時間較短的服務器會得到更多的請求,以提高系統整體的響應速度。

這些算法可以單獨使用,也可以結合使用,根據實際需求和場景進行選擇和配置。另外,現代的負載均衡器通常會結合實時監測和自動調整策略,根據服務器的負載情況動態地調整請求分發策略,以實現更智能和自適應的負載均衡。

4.Redis集羣部署方式?

Redis集羣主要有以下三種模式:

  1. 主從複製(Master-Slave Replication):這是最簡單的 Redis 集羣部署方式。在主從複製中,一個節點作爲主節點(master),負責處理寫操作和讀操作的部分負載;而其他節點作爲從節點(slaves),複製主節點的數據,並負責讀操作的負載。主節點負責寫操作的原始數據,而從節點通過異步複製主節點的數據來提供讀操作的負載均衡和高可用性。
  2. 哨兵模式(Sentinel):Sentinel 模式用於提供 Redis 的高可用性。在這種部署方式中,有多個 Redis 實例,其中一個充當主節點,負責處理寫操作和讀操作的部分負載。同時,還有多個 Sentinel 節點,它們監控主節點的狀態,並在主節點故障時自動將從節點提升爲新的主節點。這種方式可以實現故障切換和自動恢復。
  3. Redis Cluster 模式:Redis Cluster 是 Redis 官方提供的分佈式集羣解決方案。它通過分區(sharding)將數據分佈在多個節點上,每個節點負責一部分數據。Redis Cluster 使用哈希槽(hash slots)來管理數據分佈,並在節點故障時進行自動遷移和重新分配。客戶端可以直接連接到任何一個節點,節點會協調數據的讀寫操作。

5.MySQL主從複製?

MySQL 主從複製是一種常見的數據複製技術,用於實現 MySQL 數據庫的高可用性、讀寫分離和數據備份等需求。在主從複製中,有一個主數據庫(Master)和一個或多個從數據庫(Slaves)。

MySQL 主從複製在確保了主服務器(Master)和從服務器(Slave)網絡連接正常,可以互相訪問的情況下,通過配置(主要是主服務器開啓 bin log),從服務同步 bin log 的方式就可以實現主從複製了。

5.1 配置流程

主從複製的設置步驟如下:

  1. 配置主數據庫:在主數據庫上啓用二進制日誌,設置一個唯一的服務器ID,並在需要複製的數據庫中創建一個專門用於複製的賬戶。
  2. 配置從數據庫:在從數據庫上設置一個唯一的服務器ID,並配置連接主數據庫的相關參數,如主數據庫的IP地址、賬戶信息等。
  3. 啓動主從複製:在從數據庫上啓動複製進程,連接到主數據庫並開始複製主數據庫的數據。

一旦主從複製設置完成,主數據庫上的寫操作將自動複製到從數據庫上,從而實現數據的同步複製。應用程序可以通過讀寫分離的方式,將讀操作發送到從數據庫上,以提高系統的讀性能。

5.2 優缺點分析

主從複製具有以下優點:

  1. 高可用性:當主數據庫發生故障時,可以快速切換到從數據庫作爲新的主數據庫,實現故障切換,從而提高系統的可用性。
  2. 讀寫分離:可以將讀操作分發到從數據庫上,減輕主數據庫的負載,提高整體的讀性能。
  3. 數據備份:從數據庫可以作爲主數據庫的備份,用於恢復數據和災難恢復。

需要注意的是,主從複製並不適用於所有的場景,它具有一些限制和注意事項,如主從延遲、數據一致性、主數據庫的單點故障等。因此,在使用主從複製時,需要仔細考慮系統需求和架構,並進行適當的監控和維護。

6.口頭手撕快排

快速排序是一種分治算法,它通過將一個數組分成較小的子數組,然後遞歸地對子數組進行排序,最後將子數組的結果合併起來,從而達到整體有序的目的。

快速排序的實現步驟:

  1. 選擇一個基準元素(pivot),通常是選擇數組中的第一個元素或最後一個元素。
  2. 將數組分成兩個子數組,小於等於基準元素的放在左邊,大於基準元素的放在右邊。
  3. 對左右兩個子數組遞歸地應用快速排序算法。
  4. 將左子數組、基準元素和右子數組合並起來,得到最終的排序結果。

以下是 Java 實現的快排基本代碼:

public class QuickSort {
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            int pivotIndex = partition(arr, low, high);
            quickSort(arr, low, pivotIndex - 1);
            quickSort(arr, pivotIndex + 1, high);
        }
    }

    private static int partition(int[] arr, int low, int high) {
        int pivot = arr[high];
        int i = low - 1;

        for (int j = low; j < high; j++) {
            if (arr[j] <= pivot) {
                i++;
                swap(arr, i, j);
            }
        }

        swap(arr, i + 1, high);
        return i + 1;
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    public static void main(String[] args) {
        int[] arr = {5, 2, 9, 1, 7, 6, 3};
        quickSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }
}

7.隊列實現棧和棧實現隊列

7.1 隊列實現棧

隊列實現棧的基本思路是使用兩個隊列來模擬棧的行爲,通過這種方式,可以實現棧的“先進後出”(Last In First Out,LIFO)的特性。

實現思路

  1. 初始化兩個隊列,記爲 queue1 和 queue2。
  2. 當執行 push 操作時,將元素添加到 queue1 中。
  3. 當執行 pop 操作時,首先將 queue1 中的元素依次出隊併入隊到 queue2 中,直到 queue1 中只剩下一個元素。這個剩下的元素就是需要出棧的元素,將其移除並返回。
  4. 交換 queue1 和 queue2 的引用,使得 queue1 成爲主隊列,即 queue1 始終保持非空,而 queue2 作爲輔助隊列。
  5. top 操作則返回 queue1 中的最後一個元素,即棧頂元素。
  6. empty 操作則判斷 queue1 是否爲空。

實現代碼

import java.util.LinkedList;
import java.util.Queue;

public class StackUsingQueue {
    private Queue<Integer> queue1;
    private Queue<Integer> queue2;
    private int top;

    public StackUsingQueue() {
        queue1 = new LinkedList<>();
        queue2 = new LinkedList<>();
    }

    public void push(int x) {
        queue1.add(x);
        top = x;
    }

    public int pop() {
        while (queue1.size() > 1) {
            top = queue1.remove();
            queue2.add(top);
        }
        int value = queue1.remove();

        Queue<Integer> temp = queue1;
        queue1 = queue2;
        queue2 = temp;

        return value;
    }

    public int top() {
        return top;
    }

    public boolean empty() {
        return queue1.isEmpty();
    }
}

7.2 棧實現隊列

棧是一種後進先出(LIFO)的數據結構,而隊列是一種先進先出(FIFO)的數據結構。爲了實現一個隊列,我們可以使用兩個棧來模擬。

實現思路

以下是使用兩個棧實現隊列的思路:

  1. 定義兩個棧,分別稱爲"輸入棧"(input stack)和"輸出棧"(output stack)。
  2. 當有新元素進入隊列時,將其壓入輸入棧。
  3. 當需要出隊列時,如果輸出棧爲空,將輸入棧中的所有元素彈出並依次壓入輸出棧。這樣,輸出棧的頂部元素即爲隊列的第一個元素,可以出隊列。如果輸出棧不爲空,直接彈出輸出棧的頂部元素。
  4. 當需要獲取隊列的第一個元素時,執行步驟 3 中的操作,保證輸出棧的頂部元素爲隊列的第一個元素。

這種實現方式的思路是,使用輸入棧來保存新進入隊列的元素,而輸出棧則負責提供隊列的第一個元素和出隊列操作。當輸出棧爲空時,需要將輸入棧的元素轉移到輸出棧中,以保證隊列的順序。

實現代碼

import java.util.Stack;

class MyQueue {
    private Stack<Integer> stack1; // 用於入隊操作
    private Stack<Integer> stack2; // 用於出隊操作

    /** 初始化隊列數據結構 */
    public MyQueue() {
        stack1 = new Stack<>();
        stack2 = new Stack<>();
    }

    /** 入隊操作 */
    public void push(int x) {
        stack1.push(x);
    }

    /** 出隊操作 */
    public int pop() {
        if (stack2.isEmpty()) {
            // 將 stack1 中的元素依次彈出並壓入 stack2
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }

    /** 獲取隊頭元素 */
    public int peek() {
        if (stack2.isEmpty()) {
            // 將 stack1 中的元素依次彈出並壓入 stack2
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.peek();
    }

    /** 判斷隊列是否爲空 */
    public boolean empty() {
        return stack1.isEmpty() && stack2.isEmpty();
    }
}

public class Main {
    public static void main(String[] args) {
        MyQueue queue = new MyQueue();
        queue.push(1);
        queue.push(2);
        queue.push(3);
        System.out.println(queue.pop()); // 輸出:1
        System.out.println(queue.peek()); // 輸出:2
        System.out.println(queue.empty()); // 輸出:false
    }
}

8.進程有幾種狀態?

進程在操作系統中可以處於以下幾種狀態:

  1. 創建(Created):進程正在被創建,但尚未開始執行。
  2. 就緒(Ready):進程已經創建並分配了所有必要的資源,等待被調度器選中並分配CPU資源開始執行。
  3. 運行(Running):被調度器選中的進程正在執行,並佔用CPU資源。
  4. 阻塞(Blocked):進程由於某些原因無法繼續執行,例如等待外部事件的發生(如輸入/輸出操作)或等待資源的釋放。在此狀態下,進程暫時停止執行,直到滿足某些條件後才能切換到就緒狀態。
  5. 終止(Terminated):進程執行完成或被操作系統終止,釋放所有分配的資源。

9.Spring Boot Actuator?

Spring Boot Actuator 爲 Spring Boot 框架提供了強大的功能,用於監控和管理 Spring Boot 應用程序。它提供了一系列的 REST API,可以讓開發者通過 HTTP 請求來獲取應用程序的運行時信息,如健康狀況、內存使用情況、線程信息、日誌等。同時,Actuator 還支持自定義的端點,可以根據項目需求添加自定義的監控和管理功能。通過 Actuator,開發者可以方便地監控和管理應用程序的運行狀態,以及進行一些特定的操作,如動態修改日誌級別、重新加載配置等。

Spring Boot Actuator 更多內容可訪問:https://juejin.cn/post/7052857798530433031#heading-7

10.外鍵、主鍵和索引?

在數據庫中,外鍵、主鍵和索引是三個不同的概念。

  1. 主鍵(Primary Key):主鍵是用來唯一標識一條記錄的字段或字段組合。每張表只能有一個主鍵,主鍵的值不能重複且不能爲空。主鍵的作用是保證數據的完整性和唯一性,加快數據檢索速度。
  2. 外鍵(Foreign Key):外鍵是用來建立表與表之間的關聯關係的字段。它指向另一張表的主鍵,用來保持數據完整性和一致性。外鍵可以確保數據之間的引用關係,並且在刪除或更新操作時可以自動處理關聯表中的數據。
  3. 索引(Index):索引是爲了提高數據檢索速度而創建的數據結構。它類似於書籍的目錄,可以根據某個字段或字段組合快速定位到具體的數據記錄。索引可以加快數據檢索的速度,但會佔用額外的存儲空間,並且在插入、刪除和更新操作時會有一定的性能影響。

但在實際開發中,因爲性能的原因,所以我們很少用到真正的外鍵,也就是“物理外鍵”(使用 FOREIGN KEY 創建),而是在程序中使用邏輯外鍵來“建立”多張表的外鍵關係。
阿里巴巴《Java開發手冊》中也明確規定禁止使用數據庫的外鍵,如下圖所示:
image.png

11.TCP和UDP區別?

TCP(傳輸控制協議)和 UDP(用戶數據報協議)是兩種常用的網絡傳輸協議。

TCP 是一種面向連接的協議,它提供可靠的數據傳輸。在 TCP 通信中,數據被分成多個小片段,每個片段都會被編號和校驗,確保數據完整性。TCP 使用確認機制,確保數據的可靠性,如果發送方沒有收到確認信息,會重新發送數據。TCP還處理擁塞控制,根據網絡條件動態調整數據傳輸的速率。TCP 適用於需要保證數據完整性和可靠性的應用,如文件傳輸、電子郵件等。

UDP 是一種面向無連接的協議,它提供不可靠的數據傳輸。在 UDP 通信中,數據被封裝成數據包,直接發送給接收方,不需要建立連接。UDP 不提供數據校驗、確認機制和擁塞控制,因此傳輸速度較快,但容易發生數據丟失。UDP 適用於實時傳輸要求較高的應用,如音頻、視頻流等。

所以,總結來說:TCP 是可靠的、有序的、面向連接的傳輸協議,而 UDP 是簡單的、不可靠的、無連接的傳輸協議。選擇 TCP 還是 UDP 要根據具體的應用需求來確定。

12.說一下哈西表?

哈希表(Hash Table),也稱爲散列表,是一種常用的數據結構,用於實現鍵值對的存儲和快速檢索。

哈希表的核心思想是通過哈希函數將鍵映射到一個固定大小的數組索引上,將鍵值對存儲在該索引位置上。當需要查找或插入數據時,通過哈希函數計算出鍵對應的索引,然後在該位置上進行操作,從而實現快速的數據訪問。

哈希表的優點是在平均情況下具有常數時間複雜度 O(1) 的查找、插入和刪除操作。然而,在極端情況下,哈希衝突可能會導致性能下降,需要解決衝突的方法,如開放地址法(線性探測、二次探測等)或鏈表法(在衝突位置上使用鏈表存儲多個鍵值對)。

哈希表廣泛應用於各種編程場景中,如數據庫索引、緩存系統、編譯器中的符號表等,它提供了高效的數據訪問和操作效率。

在 Java 中,哈希表的常見實現類有 Hashtable、HashMap 和 ConcurrentHashMap。

13.避免哈希衝突方法?

解決哈希衝突的常用方法有以下三種:鏈地址法、開放地址法和再哈希法。

  1. 鏈地址法(Separate Chaining):將哈希表中的每個桶都設置爲一個鏈表,當發生哈希衝突時,將新的元素插入到鏈表的末尾。這種方法的優點是簡單易懂,適用於元素數量較少的情況。缺點是當鏈表過長時,查詢效率會降低。
  2. 開放地址法(Open Addressing):當發生哈希衝突時,通過一定的探測方法(如線性探測、二次探測、雙重哈希等)在哈希表中尋找下一個可用的位置。這種方法的優點是不需要額外的存儲空間,適用於元素數量較多的情況。缺點是容易產生聚集現象,即某些桶中的元素過多,而其他桶中的元素很少。
  3. 再哈希法(Rehashing):當發生哈希衝突時,使用另一個哈希函數計算出一個新的哈希值,然後將元素插入到對應的桶中。這種方法的優點是簡單易懂,適用於元素數量較少的情況。缺點是需要額外的哈希函數,且當哈希函數不夠隨機時,容易產生聚集現象。

在 Java 中,HashMap 使用的是鏈地址法來解決哈希衝突的。

14.說一下JVM?

JVM(Java Virtual Machine,Java虛擬機)是 Java 程序的運行環境,它負責將 Java 字節碼翻譯成機器代碼並執行。也就是說 Java 代碼之所以能夠運行,主要是依靠 JVM 來實現的。

JVM 整體的大概執行流程是這樣的:

  1. 程序在執行之前先要把 Java 代碼轉換成字節碼(class 文件),JVM 首先需要把字節碼通過一定的方式類加載器(ClassLoader) 把文件加載到內存中運行時數據區(Runtime Data Area)
  2. 但字節碼文件是 JVM 的一套指令集規範,並不能直接交個底層操作系統去執行,因此需要特定的命令解析器,也就是 JVM 的執行引擎(Execution Engine)會將字節碼翻譯成底層系統指令再交由 CPU 去執行;
  3. 在執行的過程中,也需要調用其他語言的接口,如通過調用本地庫接口(Native Interface) 來實現整個程序的運行。

JVM 具有以下特點:

  1. 平臺無關性:JVM 使得 Java 程序可以在不同的操作系統和硬件平臺上運行,而不需要重新編譯和調整。
  2. 安全性:JVM 可以對 Java 程序進行安全管理,防止惡意代碼的攻擊和破壞。
  3. 內存管理:JVM 可以自動管理內存,包括分配和回收內存空間,以避免內存泄漏和崩潰。
  4. 字節碼執行:JVM 可以執行 Java 字節碼文件,而不需要解釋器或編譯器。

JVM 的實現有多種標準和非標準的方式,包括 HotSpot JVM、GraalVM、Jython 和 JRuby 等。不同的 JVM 實現有不同的性能和功能特性,需要根據具體的應用場景進行選擇。

JVM 內存佈局共有以下 5 部分:

  1. 程序計數器(Program Counter Register):用於記錄當前線程執行的字節碼指令地址,是線程私有的,線程切換不會影響程序計數器的值。
  2. Java 虛擬機棧(Java Virtual Machine Stacks):用於存儲方法執行時的局部變量表、操作數棧、動態鏈接、方法出口等信息,也是線程私有的。每個方法在執行時都會創建一個棧幀,棧幀包含了方法的局部變量表、操作數棧等信息。
  3. 本地方法棧(Native Method Stack):與 Java 虛擬機棧類似,用於存儲本地方法的信息。
  4. Java 堆(Java Heap):用於存儲對象實例和數組,是 JVM 中最大的一塊內存區域,它是所有線程共享的。堆通常被劃分爲年輕代和老年代,以支持垃圾回收機制。
  • 年輕代(Young Generation):用於存放新創建的對象。年輕代又分爲 Eden 區和兩個 Survivor 區(通常是一個 From 區和一個 To 區),對象首先被分配在 Eden 區,經過垃圾回收後存活的對象會被移到 Survivor 區,經過多次回收後仍然存活的對象會晉升到老年代。
  • 老年代(Old Generation):用於存放存活時間較長的對象。老年代主要存放長時間存活的對象或從年輕代晉升過來的對象。
  1. 方法區(Methed Area):用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。方法區也是所有線程共享的。

15.項目中使用了哪些設計模式?

回答此問題,可以從一些常用的設計模式入手,比如以下這些:

  1. 單例模式:因爲項目是 Spring Boot 項目,所以默認注入的所有對象都是單例模式,或者說項目中的某一個類就是通過雙重效驗鎖的方式實現了單例模式。
  2. 工廠模式:項目中使用了線程池來實現一個接口的多個數據組裝,之後再統一返回結果的,而線程池是通過默認的線程工廠實現的,所以也使用到了工廠模式。
  3. 觀察者模式:如果項目中使用了 Spring Event 或者 Google Guava EventBus,那麼就可以說你項目中使用了觀察者模式,因爲 Event(事件)本身是基於觀察者模式實現的。
  4. 發佈訂閱者模式:如果你的項目中使用了消息中間件,比如 Kafka、RabbitMQ、RocketMQ 等,那麼你就可以說你的項目中使用了發佈、訂閱者模式,因爲消息隊列本身就是發佈訂閱者模式。
  5. 策略模式:策略模式定義了一系列的算法,把它們一個個封裝起來,並且使它們可以互相替換。策略模式的重心不是如何實現算法,而是如何組織、調用這些算法,從而讓程序結構更靈活、可維護、可擴展。比如用戶登錄包含了:賬號密碼登錄、手機驗證碼登錄和第三方登錄等,我們把不同的登錄方式封裝成不同的登錄策略,這就是策略模式。
  6. 模板方法模式:它在超類中定義了一個算法的框架,允許子類在不修改結構的情況下重寫算法的特定步驟。比如後臺的數據上傳功能,既支持 DOC 格式,又支持 CSV 格式,那麼我們就在超類中定義執行的步驟,然後再實現各自類中重寫讀取方法,因爲 DOC 和 CSV 的讀寫方法是不同的,這就是典型的模板方法模式。

16.什麼是線程安全?

線程安全是指在多線程環境下,程序的行爲不會被其他線程的干擾所影響,保證了多個線程同時訪問共享資源時的正確性和可靠性。

在 Java 中,爲了保證線程安全,可以使用 synchronized 關鍵字或者 Lock 接口來實現同步。synchronized 關鍵字可以保證同一時刻只有一個線程能夠訪問共享資源,而 Lock 接口則提供了更加靈活的控制方式。

小結

TP-LINK 總體面試難度一般,可能是因爲面試時間的原因,所以很多知識的底層實現和細節問的比較少,這對於大部分應聘者來說是好事。所以機會比能力更重要,而投遞簡歷的數量決定了機會的多少,所以抓緊投遞簡歷吧。


本文已收錄到我的面試小站 www.javacn.site,其中包含的內容有:Redis、JVM、併發、併發、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、設計模式、消息隊列等模塊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章