天天看點

【Java】留下沒有基礎眼淚的面試題前言一、如何減少線程上下文切換二、計算機網絡1已收到ack确認的資料。2發還沒收到ack的。3在視窗中還沒有發出的(接收方還有空間)。4視窗以外的資料(接收方沒空間)三、作業系統3.1僵屍程序和孤兒程序是什麼(差別)四、拓展閱讀最後

前言

隻有光頭才能變強

本文力求簡單講清每個知識點,希望大家看完能有所收獲

一、如何減少線程上下文切換

使用多線程時,不是多線程能提升程式的執行速度,使用多線程是為了更好地利用CPU資源!

程式在執行時,多線程是CPU通過給每個線程配置設定CPU時間片來實作的,時間片是CPU配置設定給每個線程執行的時間,因時間片非常短,是以CPU通過不停地切換線程執行。

線程不是越多就越好的,因為線程上下文切換是有性能損耗的,在使用多線程的同時需要考慮如何減少上下文切換

一般來說有以下幾條經驗

  • 無鎖并發程式設計。多線程競争時,會引起上下文切換,是以多線程處理資料時,可以用一些辦法來避免使用鎖,如将資料的ID按照Hash取模分段,不同的線程處理不同段的資料
  • CAS算法。Java的Atomic包使用CAS算法來更新資料,而不需要加鎖。
  • 控制線程數量。避免建立不需要的線程,比如任務很少,但是建立了很多線程來處理,這樣會造成大量線程都處于等待狀态
  • 協程。在單線程裡實作多任務的排程,并在單線程裡維持多個任務間的切換
    • 協程可以看成是使用者态自管理的“線程”。不會參與CPU時間排程,沒有均衡配置設定到時間。非搶占式的

還可以考慮我們的應用是IO密集型的還是CPU密集型的。

  • 如果是IO密集型的話,線程可以多一些。
  • 如果是CPU密集型的話,線程不宜太多。

參考資料:

二、計算機網絡

2.1MAC位址已經是唯一了,為什麼需要IP位址?

或者可以反過來問:已經有IP位址了,為什麼需要MAC位址??在zhihu上還蠻多類似的問題的:

我來簡單總結一下為什麼有了MAC(IP)還需要IP(MAC):

  • MAC是鍊路層,IP是網絡層,每一層幹每一層的事兒,之是以在網絡上分鍊路層、網絡層(...,就是将問題簡單化。
  • 曆史的相容問題。

已經有IP位址了,為什麼需要MAC位址??

  • 現階段理由:DHCP基于MAC位址配置設定IP。

MAC位址已經是唯一了,為什麼需要IP位址?

  • MAC無網段概念,非類聚,不好管理。
如果有更好的看法,不妨在評論區下留言哦~

2.2TCP狀态

TCP 每個狀态說一下,TIME-WAIT狀态說一下

TCP總共有11個狀态,狀态之間的轉換是這樣的:

流程圖:

下面我簡單總結一下每個狀态:

  • CLOSED:初始狀态,表示TCP連接配接是“關閉着的”或“未打開的”。
  • LISTEN:表示伺服器端的某個SOCKET處于監聽狀态,可以接受用戶端的連接配接。
  • SYN-SENT:表示用戶端已發送SYN封包。當用戶端SOCKET執行connect()進行連接配接時,它首先發送SYN封包,然後随即進入到SYN_SENT狀态。
  • SYN_RCVD:表示伺服器接收到了來自用戶端請求連接配接的SYN封包。當TCP連接配接處于此狀态時,再收到用戶端的ACK封包,它就會進入到ESTABLISHED狀态。
  • ESTABLISHED:表示TCP連接配接已經成功建立。
  • FIN-WAIT-1:第一次主動請求關閉連接配接,等待對方的ACK響應。
  • CLOSE_WAIT:對方發了一個FIN封包給自己,回應一個ACK封包給對方。此時進入CLOSE_WAIT狀态。
    • 接下來呢,你需要檢查自己是否還有資料要發送給對方,如果沒有的話,那你也就可以

      close()

      這個SOCKET并發送FIN封包給對方,即關閉自己到對方這個方向的連接配接
  • FIN-WAIT-2:主動關閉端接到ACK後,就進入了FIN-WAIT-2。在這個狀态下,應用程式還有接受資料的能力,但是已經無法發送資料。
  • LAST_ACK:當被動關閉的一方在發送FIN封包後,等待對方的ACK封包的時候,就處于LAST_ACK 狀态
  • CLOSED:當收到對方的ACK封包後,也就可以進入到CLOSED狀态了。
  • TIME_WAIT:表示收到了對方的FIN封包,并發送出了ACK封包。TIME_WAIT狀态下的TCP連接配接會等待

    2*MSL

  • CLOSING:罕見的狀态。表示雙方都正在關閉SOCKET連接配接

TIME_WAIT狀态一般用來處理以下兩個問題:

  • 關閉TCP連接配接時,確定最後一個ACK正常運輸(或者可以認為是:等待以便重傳ACK)
  • 網絡上可能會有殘餘的資料包,為了能夠正常處理這些殘餘的資料包。使用TIME-WAIT狀态可以確定在建立新連接配接時,先前網絡中殘餘的資料都丢失了。
TIME_WAIT過多怎麼解決?

如果在高并發,多短連結情景下,TIME_WAIT就會過多。

可以通過調整核心參數解決:

vi /etc/sysctl.conf

加入以下内容設定:

  • reuse是表示是否允許重新應用處于TIME-WAIT狀态的socket用于新的TCP連接配接;
  • recyse是加速TIME-WAIT sockets回收

我們可以知道TIME_WAIT狀态是主動關閉連接配接的一方出現的,我們不要輕易去使用上邊兩個參數。先看看是不是可以重用TCP連接配接來盡量避免這個問題(比如我們HTTP的KeepAlive)~

2.3TCP滑動視窗

TCP是一個可靠的傳輸協定,它要保證所有的資料包都可以到達,這需要重傳機制來支撐。

重傳機制有以下幾種:

  • 逾時重傳
  • 快速重傳
  • SACK 方法

滑動視窗可以說是TCP非常重要的一個知識點。TCP的滑動視窗主要有兩個作用:

  • 提供TCP的可靠性
  • 提供TCP的流控特性

簡略滑動視窗示意圖:

詳細滑動視窗示意圖:

  • 1已收到ack确認的資料。

  • 2發還沒收到ack的。

  • 3在視窗中還沒有發出的(接收方還有空間)。

  • 4視窗以外的資料(接收方沒空間)

接受端控制發送端的圖示:

2.4擁塞控制

TCP不是一個自私的協定,當擁塞發生的時候,要做自我犧牲。就像交通阻塞一樣,每個車都應該把路讓出來,而不要再去搶路了

擁塞控制主要是四個算法:

  • 1)慢啟動,
  • 2)擁塞避免,
  • 3)擁塞發生,
  • 4)快速恢複

擁塞控制的作用:

擁塞的判斷:

  • 重傳定時器逾時
  • 收到三個相同(重複)的 ACK

強烈建議閱讀:

三、作業系統

3.1僵屍程序和孤兒程序是什麼(差別)

unix/linux環境下

僵屍程序:

  • 父程序建立出子程序,子程序退出了,父程序沒有調用

    wait

    waitId

    擷取子程序的資訊(狀态),子程序的描述符仍在系統中。

孤兒程序:

  • 父程序退出,子程序仍在運作中。這些子程序就叫做孤兒程序,孤兒程序将被init程序(程序号為1)所收養,并由init程序對它們完成狀态收集工作

僵屍程序危害:

  • 系統程序表是一項有限資源,如果系統程序表被僵屍程序耗盡的話,系統就可能無法建立新的程序。
  • 一個父程序建立了很多子程序,就是不回收,會造成記憶體資源的浪費。

解決僵屍程序的手段:

  • 殺掉父程序,餘下的僵屍程序會成為孤兒程序,最後被init程序管理
  • 子程序退出時向父程序發送SIGCHILD信号,父程序處理SIGCHILD信号。在信号處理函數中調用wait進行處理僵屍程序
  • fork兩次:原理是将子程序成為孤兒程序,進而其的父程序變為init程序,通過init程序可以處理僵屍程序

3.2作業系統程序間通信的方式有哪些?

首先要知道的是:程序和線程的關注點是不一樣的:

  • 程序間資源是獨立的,關注的是通訊問題。
  • 線程間資源是共享的,關注的是安全問題。
作業系統程序間通信的方式有哪些?
  • 管道(pipe):管道是一種半雙工的通信方式,資料隻能單向流動,而且隻能在具有親緣關系的程序間使用。程序的親緣關系通常是指父子程序關系。
  • 有名管道(named pipe):有名管道也是半雙工的通信方式,但是它允許無親緣關系程序之間的通信。
  • 消息隊列(message queue):消息隊列是消息的連結清單,存放在核心中并由消息隊清單示符标示。消息隊列克服了信号傳遞資訊少,管道隻能承載無格式位元組流以及緩沖區大小受限制等缺點。
  • 共享記憶體(shared memory):共享記憶體就是映射一段内被其它程序所通路的記憶體,共享記憶體由一個程序建立,但是多個程序都可以通路。共享記憶體是最快的IPC,它是針對其它程序通信方式運作效率低的而專門設計的。它往往與其它通信機制。如信号量,配合使用,來實作程序間的同步和通信。
  • 套接字(socket):套接字也是程序間的通信機制,與其它通信機制不同的是,它可以用于不同機器間的程序通信。
  • 信号(signal):信号是一種比較複雜的通信方式,用于通知接受程序程序某個時間已經發生。
  • 信号量(semaphore):信号量是一個計數器,可以用來控制多個程序對共享資源的通路。
    • 它常作為一種鎖的機制,防止某程序正在通路共享資源時,其它程序也通路該資源。是以它主要作為不同程序或者同一程序之間不同線程之間同步的手段。

3.3作業系統線程間通信的方式有哪些?

作業系統線程間通信的方式有哪些?(可以直接了解成:線程之間同步的方式有哪些)
  • 鎖機制:包括互斥鎖、條件變量、讀寫鎖
  • 信号量機制(Semaphore):包括無名線程信号量和命名線程信号量
  • 信号機制(Signal):類似程序間的信号處理

線程間的通信目的主要是用于線程同步。

擴充閱讀:

3.4作業系統程序排程算法有哪些?

作業系統程序排程算法有哪些?
  • 先來先服務算法(FCFS)
    • 誰先來,就誰先執行
  • 短程序/作業優先算法(SJF)
    • 誰用的時間少、就先執行誰
  • 最高響應比優先算法(HRN)
    • 對FCFS方式和SJF方式的一種綜合平衡
  • 最高優先數算法
    • 系統把處理機配置設定給就緒隊列中優先數最高的程序
  • 基于時間片的輪轉排程算法
    • 每個程序所享受的CPU處理時間都是一緻的
  • 最短剩餘時間優先算法
    • 短作業優先算法的更新版,隻不過它是搶占式的
  • 多級回報排隊算法
    • 設定多個就緒隊列,分别賦予不同的優先級,如逐級降低,隊列1的優先級最高

參考筆記:

四、拓展閱讀

此部分是看别人的博文已經寫得很好了,分享給大家~

4.1ConcurrentHashMap中的擴容是否需要對整個表上鎖?

ConcurrentHashMap中的擴容是否需要對整個表上鎖?

總結(摘抄)要點:

  • 通過給每個線程配置設定桶區間(預設一個線程配置設定的桶是16個),避免線程間的争用。
  • 通過為每個桶節點加鎖,避免 putVal 方法導緻資料不一緻。
  • 同時,在擴容的時候,也會将連結清單拆成兩份,這點和 HashMap 的 resize 方法類似。

4.2什麼是一緻性Hash算法(原理)?

什麼是一緻性Hash算法(原理)?
  • 一緻性Hash算法将整個哈希值空間組織成一個虛拟的圓環,好處就是提高容錯性和可擴充性。
    • 對于節點的增減都隻需重定位環空間中的一小部分資料。

4.3MySQL date、datetime和timestamp類型的差別

MySQL date、datetime和timestamp類型的差別
  • date精确到天,datetime和timestamp精确到秒
  • datetime和timestamp的差別:
    • timestamp會跟随設定的時區變化而變化,而datetime儲存的是絕對值不會變化
    • timestamp儲存占用4個位元組,datetime儲存占用8個位元組
    • 可表示的時間範圍不同,timestamp隻能到表示到2038年,datetime可到9999年

4.4判斷一個連結清單是否有環/相交

判斷一個連結清單是否有環(實際上就是看看有無周遊到重複的節點),解決方式(3種):

  1. for周遊兩次
  2. 使用hashSet做緩存,記錄已周遊過的節點
  3. 使用兩個指針,一前一後周遊,總會出現

    前指針==後指針

    的情況

判斷兩個無環連結清單是否相交,解決方式(2種):

  • 将第一個連結清單尾部的next指針指向第二個連結清單,兩個連結清單組成一個連結清單。
    • 判斷這一個連結清單是否有環,有環則相交,無環則不相交
  • 直接判斷兩個連結清單的尾節點是否相等,如果相等則相交,否則不相交

判斷兩個有環連結清單是否相交(注:當一個連結清單中有環,一個連結清單中沒有環時,兩個連結清單必不相交):

  • 找到第一個連結清單的環點,然後将環斷開(當然不要忘記了儲存它的下一個節點),然後再來周遊第二個連結清單,如果發現第二個連結清單從有環變成了無環,那麼他們就是相交的嘛,否則就是不相交的了。

4.5keepAlive含義

  • HTTP協定的Keep-Alive意圖在于連接配接複用,同一個連接配接上串行方式傳遞請求-響應資料
  • TCP的KeepAlive機制意圖在于保活、心跳,檢測連接配接錯誤

最後

如果大家有更好的了解方式或者文章有錯誤的地方還請大家不吝在評論區留言,大家互相學習交流~~~

如果想看更多的原創技術文章,歡迎大家關注我的微信公衆号:Java3y。Java技術群讨論:742919422。公衆号還有海量的視訊資源哦,關注即可免費領取。

可能感興趣的連結: