本期是【大廠面試】系列文章的第4期,題目出自美團到店二面。
面試現場
面試官:首先你來講講程式和執行緒有什麼區別?
獨白:老八股文了哈哈
大彬:程式是系統進行資源分配和排程的獨立單位,每一個程式都有自己的記憶體空間和系統資源
大彬:執行緒是程式的一個實體,是CPU排程和分派的基本單位,它是比程式更小的能獨立執行的基本單位
大彬:多執行緒是實現併發機制的一個有效手段。程式和執行緒一樣都是實現併發的基本單位
面試官:那為什麼要用多執行緒呢?
獨白:嘿嘿,這個簡單
大彬:使用多執行緒最主要的原因是提高系統的資源利用率。
大彬:多個執行緒同時執行,可以減少執行緒上下文切換的開銷,提高併發的能力和CPU的利用效率。
大彬:在平時工作中多執行緒也是常見的。比如Tomcat每處理一個請求都會從執行緒連線池裡取一個執行緒去處理。
面試官:嗯,平時在使用多執行緒的時候,可能會遇到執行緒安全的問題吧。講講什麼是執行緒安全?
大彬:我是這麼理解的,當多個執行緒訪問一個物件時,如果不用考慮這些執行緒在執行時環境下的排程和交替執行,也不需要進行額外的同步,呼叫這個物件的行為都可以獲得正確的結果,那這個物件就是執行緒安全的。
面試官:那你平時怎麼處理執行緒安全問題的?
大彬:這個還得具體問題具體分析。首先判斷有沒有執行緒安全問題,若有則根據具體的情況去處理執行緒安全的問題。
大彬:比如涉及到操作的原子性,可以考慮使用atomic
包下的原子類。
大彬:如果涉及到對執行緒的控制,可以考慮執行緒工具類CountDownLatch
/Semaphore
等等。
大彬:集合類的話,考慮java.util.concurrent
包下的集合類。
大彬:還有synchronized
和lock
包下的類,redis分散式鎖等。
面試官:嗯哼,剛提到Redis分散式鎖,你覺得什麼場景下需要使用分散式鎖呢?
大彬:在單機環境下,執行緒安全問題可以通過ReentrantLock
、synchronized
以及 concurrent
併發包下一些執行緒安全的類等來避免。
大彬:而在多機部署環境,需要在多程式下保證執行緒的安全性,Java提供的這些API僅能保證在單個JVM程式內對多執行緒訪問共享資源的執行緒安全,已經不滿足需求了。這時候就需要使用分散式鎖來保證執行緒安全。
大彬:Redis 2.6.12 之前的版本中採用 setnx + expire
方式實現分散式鎖。在 Redis 2.6.12 版本後 setnx
增加了過期時間引數,只需要使用setnx
就可以實現分散式鎖了。
面試官:那再講講Redis分散式鎖的原理?
獨白:面試造火箭,入職擰螺絲?
大彬:首先介紹下Redis的加鎖邏輯。
大彬:setnx
爭搶key的鎖,如果已有key存在,則不作操作,過段時間繼續重試,保證只有一個客戶端能持有鎖。
大彬:value設定為 requestId
(可以使用機器ip拼接當前執行緒名稱),表示這把鎖是哪個請求加的,在解鎖的時候需要判斷當前請求是否持有鎖,防止誤解鎖。比如客戶端A加鎖,在執行解鎖之前,鎖過期了,此時客戶端B嘗試加鎖成功,然後客戶端A再執行del()
方法,則將客戶端B的鎖給解除了。
大彬:再用expire
給鎖加一個過期時間,防止異常導致鎖沒有釋放。
大彬:然後是解鎖邏輯。
大彬:首先獲取鎖對應的value值,檢查是否與requestId
相等,如果相等則刪除鎖。使用lua指令碼實現原子操作,保證執行緒安全。
面試官:不錯,看你簡歷上寫了熟悉TCP,來介紹下TCP四次揮手?
獨白:嗯,這個嘛,很熟悉
大彬:假設A是client端,B是server端。
- 首先A的應用程式先向其TCP發出連線釋放報文段(
FIN=1,seq=u
),並停止再傳送資料,主動關閉TCP連線,進入FIN-WAIT-1
(終止等待1)狀態,等待B的確認。 - B收到連線釋放報文段後即發出確認報文段(
ACK=1,ack=u+1,seq=v
),B進入CLOSE-WAIT
(關閉等待)狀態,此時的TCP處於半關閉狀態,A到B的連線釋放。 - A收到B的確認後,進入
FIN-WAIT-2
(終止等待2)狀態,等待B發出的連線釋放報文段。 - B傳送完資料,就會發出連線釋放報文段(
FIN=1,ACK=1,seq=w,ack=u+1
),B進入LAST-ACK
(最後確認)狀態,等待A的確認。 - A收到B的連線釋放報文段後,對此發出確認報文段(
ACK=1,seq=u+1,ack=w+1
),A進入TIME-WAIT
(時間等待)狀態。此時TCP未釋放掉,需要經過時間等待計時器設定的時間2MSL
(最大報文段生存時間)後,A才進入CLOSED
狀態。B收到A發出的確認報文段後關閉連線,若沒收到A發出的確認報文段,B就會重傳連線釋放報文段。
面試官:建立連線時三次握手,為什麼連線釋放要四次揮手,三次不行嗎?
大彬:因為建立連線時,當Server端收到Client端的SYN
連線請求報文後,可以直接傳送SYN+ACK
報文。
大彬:但是在關閉連線時,當Server端收到Client端發出的連線釋放報文時,很可能並不會立即關閉SOCKET,所以Server端先回復一個ACK
報文,告訴Client端我收到你的連線釋放報文了。只有等到Server端所有的報文都傳送完了,這時Server端才能傳送連線釋放報文,之後兩邊才會真正的斷開連線。故需要四次揮手。
面試官:嗯,你瞭解https嗎?https是為了解決什麼問題?
獨白:一點也不慌哈哈
大彬:HTTP是明文傳輸,容易被黑客竊聽或篡改,不安全。
大彬: HTTPS 主要解決了 HTTP 明文協議的缺陷,在 HTTP 的基礎上加入 SSL/TLS 協議,依靠 SSL 證照來驗證伺服器的身份,為客戶端和伺服器端之間建立SSL通道,確保資料傳輸安全。
面試官:那http跟https具體有什麼區別呢?
大彬:http和https的區別如下:
- HTTP是超文字傳輸協議,資訊是明文傳輸;HTTPS則是具有安全性的ssl加密傳輸協議。
- HTTP和HTTPS用的埠不一樣,HTTP埠是80,HTTPS是443。
- HTTPS協議需要到CA機構申請證照,一般需要一定的費用。
- HTTP執行在TCP協議之上;HTTPS執行在SSL協議之上,SSL執行在TCP協議之上。
面試官:不錯,再來問點MySQL相關的
面試官:什麼情況下索引會失效?
大彬:主要有這麼幾種情況會導致索引失效。
- 對於組合索引,不是使用組合索引最左邊的欄位,則不會使用索引
- 以%開頭的like查詢如
%abc
,無法使用索引;非%開頭的like查詢如abc%
,相當於範圍查詢,會使用索引 - 查詢條件中列型別是字串,沒有使用引號,可能會因為型別不同發生隱式轉換,使索引失效
- 判斷索引列是否不等於某個值時
- 對索引列進行運算
- 查詢條件使用
or
連線,也會導致索引失效
面試官:很好,明天能入職嗎?
獨白:馬甲頭盔箱子三件套?