軟體工程師面試常見題目

軟件工程師面試常見題目

軟件工程師面試常見題目

一 計算機網絡

1. TCP三次握手, 四次揮手, TIME_WAIT狀態.

三次握手:

(1)客戶端發出連接請求報文, SYN=1(同步位), seq=x(初始序號),客戶進程進入SYN-SENT狀態

(2)服務器端收到請求報文, 發送確認報文, 確認報文中SYN=1,ACK=1, 確認號ack=x+1,同時選擇一個初始序號seq=y, 服務器進程進入SYN-RCVD狀態

(3)客戶端進程收到確認後, 再發出確認, 確認報文ACK置1, 確認號ack=y+1, 自己的序號是seq=x+1, 客戶端進程進入EXTABLISHED狀態(已連接),服務器端進程收到報文後進入EXTABLISHED狀態

補充 :

為什麼要三次握手,而不是二次握手呢?

採用三次握手的目的是為了防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤

四次揮手 :

(1)客戶端進程發出連接釋放報文段, 並停止發送數據, 將FIN置1, seq=u, 進入FIN-WAIT-1狀態

(2)服務器端進程收到釋放報文段發出確認, ACK置為1, ack=u+1, seq=v,進入CLOSE-WAIT狀態, 此時客戶端到服務器端的連接就釋放了, 服務器需通知高應用層的進程(不能向客戶端進程發送數據了), 客戶端收到確認報文後進入FIN-WAIT-2狀態並等待服務器發出連接釋放報文段.

(3)若服務器沒有數據發送給客戶端進程了, 發出釋放報文段, FIN=1, 序號seq=w, 客戶端還得繼續重複發送過的報文段確認號ack=u+1, 之後服務器端進程進入LAST-ACK狀態.

(4)客戶端進程收到釋放報文段,發出確認, ACK置1, ack=w+1, seq=u+1然後客戶端進程進入TIME-WAIT狀態, 客戶端需等待2MSL時間後才進入CLOSED狀態, 服務器端收到確認報文段進入CLOSED狀態.

(關於需要經過2MSL時間的說明:1.保證確認報文能夠到達服務器, 如果收不到服務器會超時重傳連接釋放報文段. 2防止失效的連接請求報文到達的情況)

2.擁塞控制,流量控制

(1)擁塞控制: 就是防止過多的數據注入到網絡中, 這樣可以使網絡中的路由器或鏈路不致過載(是一個全局性的過程)

(2)流量控制 : 往往是指點對點通信量的控制, 是個端對端的問題, 通過抑制發送端發送數據的速率, 以便接收端來得及接受

問題:理想狀態下吞吐量(網絡輸出的分組數目)是隨著網絡設備提供的負載(即單位時間內輸入給網絡的分組數目)增大而增大(比例近似1:1), 當吞吐量飽和之後, 吞吐量趨於平衡, 而實際是, 隨著負載增加吞吐量反而越來越小

(3)幾種擁塞控制方法

四種算法: 慢開始, 擁塞避免, 快重傳和快恢復

先假定條件如下:

數據總是單方面傳送, 另一方傳送確認

接收方有足夠緩存空間, 發送窗口的大小由網絡的擁塞程度來決定

1).慢開始和擁塞避免

發送方維持一個擁塞窗口cwnd(大小取決於網絡擁塞程度, 並動態變化), 發送方窗口等於擁塞窗口, 如果接收方接受能力不行, 發送窗口可能小於擁塞窗口

慢開始:

有小到大增大發送窗口(即有小到大增大擁塞窗口), 剛開始cwnd = 2MSS, 以後每接受一個報文增加一個MSS的數值(簡單起見, 以報文段的個數作為窗口大小, TCP是使用字節作為窗口單位)

例如 :

初始設置cwnd = 1, 發送報文M1;

收到報文M1確認報文, cwnd = 2, 發送M2, M3

收到M2, M3確認, cwnd = 4, 發送M4-M7….

每經過一個傳輸輪次, 擁塞串口cwnd加倍

為了防止擁塞, 設置一個慢開始門限(ssthresh):

當cwnd < ssthresh, 使用上述慢開始算法

當cwnd > ssthresh, 停止使用慢開始算法而改用擁塞避免算法

當cwnd = ssthresh, 即可使用慢開始算法, 也可以使用擁塞避免算法

擁塞避免算法:

讓擁塞窗口cwnd緩慢的增大, 每經過一個往返時間RRT就把cwnd + 1, 而不是加倍, 增長緩慢

慢開始判斷只要出現擁塞(擁塞判斷條件:發送方沒有按時收到確認), 就把慢開始門限ssthresh設置為擁塞時發送窗口的一半(ssthresh = cwnd / 2 > 2? cwnd / 2 : 2), 然後擁塞控制窗口設置為1, 執行慢開始算法(讓中間網絡設備有足夠時間把隊列中的積壓分組處理完畢)

2).快重傳和快恢復

快重傳算法是 : 要求接收方收到一個失序的報文段後就立即發出重複確認(不要發送數據時才捎帶確認, 為的是讓發送方及早知道報文段沒有到達對方), 若接收方收到三個重複確認就立即重傳對方未接收到的報文段

與快重傳配合使用的算法是快恢復:

a)當連續接收到三個重複確認, 慢開始門限ssthresh減半(接下去並不是執行慢開始算法)

b)因為能接收到連續的重複確認(即表明並沒有發生嚴重的擁塞), 不採用慢開始(即把cwnd置為1)而是把擁塞窗口置為慢開始門限減半後的數值執行擁塞避免算法, 使擁塞窗口緩慢地線性增大

3).總結迴歸實際

剛開始假定接收方擁有足夠的緩存空間, 所以發送窗口僅依賴於擁塞窗口, 但實際上發送窗口也收到接受串口rwnd的限定\

即發送方窗口上限 = Min[rwnd, cwnd]

二.Linux專區

1.Linux中用過的命令,優盤插入Linux操作系統後,是如何處理的

(1). 插入U盤

#fdisk –l (查看當前U盤的設備名稱 ) 可以清楚看到,識別當前的U盤的文件名為“/dev/sdb1”

(2). 掛載U盤

#mount -t vfat /dev/sdb1 /mnt vfat表示所有的FAT文件系統

當前U盤使用的是FAT文件系統,若使用的是NTFS文件系統則使用 mount –t ntfs /dev/sdb1 /mnt

(3).讀取

#ls /mnt/ 可以看到U盤裡面的東東了

(4).卸載

#umount /dev/sdb1

三.數據庫專區

**1.MySQL的索引實現及好處,為什麼用自增列作為主鍵?

此處引用一篇博客能很好的奠定基礎:https://www.cnblogs.com/bonelee/p/6225211.html

優點

有了索引.對於記錄數量很多的表,可以提高查詢速度.

缺點

索引是佔用空間的.

索引會影響update insert delete速度

索引最好創建在:

索引要創建在where和join用到的字段上

**

2.數據庫四大特性, 數據庫事務的隔離級別

事務的四大特性(ACID):

(1)原子性(Atomicity)

(2)一致性(Consistency)

(3)隔離性(Isolation)

(4)持久性(Durability)

不考慮事務隔離的特性將引發下列問題:

(1)髒讀:

髒讀是指在一個事務處理過程裡讀取了另一個未提交的事務中的數據

(2)不可重複讀:

不可重複讀是指在對於數據庫中的某個數據,一個事務範圍內多次查詢卻返回了不同的數據值,這是由於在查詢間隔,被另一個事務修改並提交了

(3)虛讀(幻讀):

幻讀是事務非獨立執行時發生的一種現象。例如事務T1對一個表中所有的行的某個數據項做了從“1”修改為“2”的操作,這時事務T2又對這個表中插入了一行數據項,而這個數據項的數值還是為“1”並且提交給數據庫。而操作事務T1的用戶如果再查看剛剛修改的數據,會發現還有一行沒有修改,其實這行是從事務T2中添加的,就好像產生幻覺一樣,這就是發生了幻讀.

事務的隔離級別:

① Serializable (串行化):確保事務可以從一個表中讀取相同的行, 事務持續期間禁止對該表進行插入, 更新和刪除操作, 可避免髒讀、不可重複讀、幻讀

② Repeatable read (可重複讀):確保事務可以從同一個字段中讀取相同的值, 事務持續期間禁止其他事務對該字段的更新, 但無法禁止其他事務的插入刪除操作, 可避免髒讀、不可重複讀, 但無法避免幻讀

③ Read committed (讀已提交):只允許事務讀取已提交的事務,可避免髒讀的發生但無法避免不可重複讀和幻讀

④ Read uncommitted (讀未提交):最低級別,任何情況都無法保證, 允許事務讀取其他事務未提交的數據, 出現髒讀, 不可重複讀, 幻讀

以上四種隔離級別最高的是Serializable級別,最低的是Read uncommitted級別,當然級別越高,執行效率就越低。像Serializable這樣的級別,就是以鎖表的方式(類似於Java多線程中的鎖)使得其他的線程只能在鎖外等待,所以平時選用何種隔離級別應該根據實際情況。在MySQL數據庫中默認的隔離級別為Repeatable read (可重複讀)

可參考博文 :

https://blog.csdn.net/qq_33290787/article/details/51924963

https://www.cnblogs.com/ForeverLover/p/4866354.html

3.數據庫的優化

(1)選取最適用的字段屬性(應該儘量把字段設置為NOTNULL)

(2)使用連接(JOIN)來代替子查詢(Sub-Queries)連接(JOIN)..之所以更有效率一些,是因為MySQL不需要在內存中創建臨時表來完成這個邏輯上的需要兩個步驟的查詢工作

(3)使用聯合(UNION)來代替手動創建的臨時表

(4)事務

可以使一整個的SQL語句塊都得到執行或者都不執行(從狀態到狀態的一致性轉變) .補充:事務性的獨佔性導致在高併發狀態性能較差

(5)鎖定表

有些情況下我們可以通過鎖定表的方法來獲得更好的性能

(6)使用外鍵

鎖定表的方法可以維護數據的完整性,但是它卻不能保證數據的關聯性。這個時候我們就可以使用外鍵

(7)使用索引 (索引查看語句 : show index from table_name; )

作用:索引是提高數據庫性能的常用方法,它可以令數據庫服務器以比沒有索引快得多的速度檢索特定的行,尤其是在查詢語句當中包含有MAX(),MIN()和ORDERBY這些命令的時候,性能提高更為明顯.

作用對象(列):一般說來,索引應建立在那些將用於JOIN,WHERE判斷和ORDERBY排序的字段上。儘量不要對數據庫中某個含有大量重複的值的字段建立索引。對於一個ENUM類型的字段來說,出現大量重複值是很有可能的情況

(8)優化的查詢語句

絕大多數情況下,使用索引可以提高查詢的速度,但如果SQL語句使用不恰當的話,索引將無法發揮它應有的作用

(9)慢查詢

https://www.cnblogs.com/kerrycode/p/5593204.html

4.MyIsam與Innodb分別使用場景

1)區別

(1)事務處理

MyIsam是非事務安全型, 而InnoDB是事務安全型的(支持事務處理等高級處理)

(2)鎖機制不同:

MyISAM是表級鎖,而InnoDB是行級鎖;

(3)select ,update ,insert ,delete 操作:

MyISAM:如果執行大量的SELECT,MyISAM是更好的選擇

InnoDB:如果你的數據執行大量的INSERT或UPDATE,出於性能方面的考慮,應該使用InnoDB表

(4)查詢表的行數不同:

MyISAM:select count() from table,MyISAM只要簡單的讀出保存好的行數,注意的是,當count()語句包含 where條件時,兩種表的操作是一樣的

InnoDB : InnoDB 中不保存表的具體行數,也就是說,執行select count(*) from table時,InnoDB要掃描一遍整個表來計算有多少行

(5)外鍵支持:

mysiam表不支持外鍵,而InnoDB支持

2) 為什麼MyISAM會比Innodb 的查詢速度快。

INNODB在做SELECT的時候,要維護的東西比MYISAM引擎多很多;

(1)數據塊,INNODB要緩存,MYISAM只緩存索引塊, 這中間還有換進換出的減少;

(2)innodb尋址要映射到塊,再到行,MYISAM 記錄的直接是文件的OFFSET,定位比INNODB要快

(3)INNODB還需要維護MVCC一致;雖然你的場景沒有,但他還是需要去檢查和維護

MVCC ( Multi-Version Concurrency Control )多版本併發控制

3) 應用場景

MyISAM適合:(1)做很多count 的計算;(2)插入不頻繁,查詢非常頻繁;(3)沒有事務。

InnoDB適合:(1)可靠性要求比較高,或者要求事務;(2)表更新和查詢都相當的頻繁,並且行鎖定的機會比較大的情況。

5.規範化(第一方式…第四範式)

1)函數依賴

如果存在關係r, 有相同的x則唯一確定一個y, 則稱y函數依賴與x

非平凡依賴 : x -> y, y是x的非空子集

平凡依賴 : x -> y, y是x的子集

若在R(U)中, 如果X->Y, 並對於任意一個 真子集Z不能確定Y, 則稱Y對X為完全函數依賴, 否則稱為部分函數依賴;

若有X->Y(Y 不是X的真子集, 且X不依賴於Y), Y->W(且W不是Y的真子集), 則稱W對X為傳遞函數依賴

2)碼

如果K是 R< U, F >屬性或者屬性集合, 而且U完全函數依賴於K, 則K為R的候選碼(而當U是部分函數依賴於K, 則稱K為超碼)

若候選碼有多個, 選定其中一個為主碼

包含在候選碼中的屬性稱為主屬性, 不包含在候選碼中的屬性稱為非主屬性

3)範式

1NF : 滿足最低要求的稱為第一範式

2NF : 若R屬於1NF, 且每一個非主屬性完全函數依賴於任一個候選碼, 則R屬於2NF

3NF : 若R< U, F >屬於1NF, 屬性Y及非主屬性Z(Y不是X的子集), 使得X->Y, Y->Z成立, 且X不依賴於Y, 則稱R< U, F >屬於3NF(翻譯 : 如果R屬於第三範式, 則每一個非主屬性既不傳遞依賴於碼, 也不部分依賴於碼)

BCNF : 關係模式R< U, F >屬於1NF, 若X->Y, 且Y不是X的子集時X必含有碼, 則R< U, F >屬於BCNF

解析 :

非主屬性對每一個碼都是完全函數依賴

所有的主屬性對每一個不包含它的碼也是完全函數依賴

沒有任何一組屬性完全依賴於非碼的一組屬性

4NF : 限制關係模式中的屬性之間不允許非平凡且非函數依賴的多值依賴

6.數據庫查詢不走索引的情況

1)單鍵值的b樹索引列上存在null值, 因為HASHSET中不能存儲空值導致Count(*)不能走索引.(B-tree索引is null不會走,is not null會走,位圖索引 is null,is not null 都會走索隱列避免空列,一般選非空的列)

解決 : 需要加上NOT NULL或者把列的屬性改為not null才能走索引

2)在索引列上進行函數運算或者加減乘除運算都會導致不走索引, 因為索引的存儲的值只是列的原值而不是計算結果的值.

解決 : 可以在索引列上改用簡歷基於函數的索引

3)使用or會導致不走索引, 除非是or的每個列都建立索引

4)隱式轉換導致不走索引, 原理與在索引上進行函數運算一樣

5)表的數據庫小或者需要選擇大部分數據, 不走索引(例如查詢查詢數量超過表的一部分, MySQL30%, Oracle20%)

6)在索引列使用!= 或者<>(不等於), 可能導致不走索引, 也可能走INDEX FAST FULL SCAN

7)建立組合索引, 但查詢並未使用組合索引的第一列, 此處有一個INDEX SKIP SCAN概念(最左前綴原則)

8)使用 like ‘%xxx’, 百分號在前導致不走索引, 但是使用 like ‘xxx%’可以走索引, like ‘%xxx%’也不走索引

9)使用not in, not exist不走索引

解決 : 可以嘗試吧子查詢的not in或者not exist改成左聯接的方式

10)沒有查詢條件, 查詢條件沒索引

7.MVCC : https://blog.csdn.net/whoamiyang/article/details/51901888

四.框架專區

1.mybatis的緩存,以及設計一個緩存過期後緩存的清理模塊

默認同一個sqlSession中開啟一級緩存, 需要手動配置開啟二級緩存(同一個namespace下的sqlSession共享的二級緩存)

2.Spring是如何處理循環依賴的?

3.SpringMVC與Struts2的比較總結

框架機制:

(1)Struts2採用Filter(StrutsPrepareAndExecuteFilter)實現,SpringMVC(DispatcherServlet)則採用Servlet實現

(2)Filter在容器啟動之後即初始化;服務停止以後墜毀,晚於Servlet。Servlet在是在調用時初始化,先於Filter調用,服務停止後銷燬

攔截機制:

Struts2:

a、Struts2框架是類級別的攔截,每次請求就會創建一個Action,和Spring整合時Struts2的ActionBean注入作用域是原型模式prototype(否則會出現線程併發問題),然後通過setter,getter吧request數據注入到屬性。

b、Struts2中,一個Action對應一個request,response上下文,在接收參數時,可以通過屬性接收,這說明屬性參數是讓多個方法共享的。

c、Struts2中Action的一個方法可以對應一個url,而其類屬性卻被所有方法共享,這也就無法用註解或其他方式標識其所屬方法了

SpringMVC:

a、SpringMVC是方法級別的攔截,一個方法對應一個Request上下文,所以方法直接基本上是獨立的,獨享request,response數據。而每個方法同時又何一個url對應,參數的傳遞是直接注入到方法中的,是方法所獨有的。處理結果通過ModeMap返回給框架。

b、在Spring整合時,SpringMVC的Controller Bean默認單例模式Singleton,所以默認對所有的請求,只會創建一個Controller,有應為沒有共享的屬性,所以是線程安全的,如果要改變默認的作用域,需要添加@Scope註解修改。

性能方面:

SpringMVC實現了零配置,由於SpringMVC基於方法的攔截,有加載一次單例模式bean注入。而Struts2是類級別的攔截,每次請求對應實例一個新的Action,需要加載所有的屬性值注入,所以,SpringMVC開發效率和性能高於Struts2。

攔截方面:

Struts2有自己的攔截Interceptor機制,SpringMVC這是用的是獨立的Aop方式,這樣導致Struts2的配置文件量還是比SpringMVC大。

4.Mybatis關於樂觀鎖的實現

為表的字段添加一個version字段, 在執行更新的時候驗證版本號

5.Mybatis中關於#{}與${}區別

ups_role_permission_dataparams

where role_id = #{roleId,jdbcType=INTEGER}

在這裡用到了#{},使用#時:

1)用來傳入參數,sql在解析的時候會加上” “,當成字符串來解析 ,如這裡 role_id = “roleid”;

2)#{}能夠很大程度上防止sql注入;

延伸:

1)用傳入數據直接顯示在生成的sql中,如上面的語句,用roleid=傳入數據直接顯示在生成的sql中,如上面的語句,用roleid={roleId,jdbcType=INTEGER},那麼sql在解析的時候值為role_id = roleid,執行時會報錯;

2)方式無法防止sql注入;3)方式無法防止sql注入;3)一般用入傳入數據庫對象,比如數據庫表名;

4)能用#{}時儘量用#{};

注意:

mybaties排序時使用order by 動態參數時需要注意,使用${}而不用#{};

6.Spring IOC原理

https://blog.csdn.net/it_man/article/details/4402245

五.java基礎

1.BIO與NIO的區別,NIO中select的作用?NIO中的Channel的設計模式?

IO的方式通常分為幾種,同步阻塞的BIO、同步非阻塞的NIO、異步非阻塞的AIO

連接建立的時候先在selector上註冊, 等到真正請求進來的時候selector會輪訓每個連接會被分配到線程進行處理

2.HashMap的JDK1.7,1.8實現,為什麼要用紅黑書替換,說一說紅黑樹?

即使使用再好的hash函數也可能會有大量的數據集中在幾個桶中, 在同一個桶中的話查找性能會大大降低.

3.JDBC中PreparedStatement和Statement的區別?

PreparedStatement是java.sql包下面的一個接口,用來執行SQL語句查詢,通過調用connection.preparedStatement(sql)方法可以獲得PreparedStatment對象。數據庫系統會對sql語句進行預編譯處理(如果JDBC驅動支持的話),預處理語句將被預先編譯好,這條預編譯的sql查詢語句能在將來的查詢中重用,這樣一來,它比Statement對象生成的查詢速度更快.

(1)PreparedStatement可以寫動態參數化的查詢

(2)PreparedStatement比 Statement 更快(數據庫對SQL語句的分析,編譯,優化已經在第一次查詢前完成了)

(3)PreparedStatement可以防止SQL注入式攻擊

參考:http://www.importnew.com/5006.html

4.java 線程池

(1)創建:

可以通過ThreadPoolExecutor來創建一個線程

new ThreadPoolExecutor(corePoolSize, maximumPoolSize,

keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler);

參數的意思:

corePoolSize(線程池的基本大小):當提交一個任務到線程池時,線程池會創建一個線程來執行任務,即使其他空閒的基本線程能夠執行新任務也會創建線程,等到需要執行的任務數大於線程池基本大小時就不再創建。如果調用了線程池的prestartAllCoreThreads方法,線程池會提前創建並啟動所有基本線程

runnableTaskQueue(任務隊列):用於保存等待執行的任務的阻塞隊列。可以選擇以下幾個阻塞隊列

ArrayBlockingQueue:是一個基於數組結構的有界阻塞隊列,此隊列按 FIFO(先進先出)原則對元素進行排序。

LinkedBlockingQueue:一個基於鏈表結構的阻塞隊列,此隊列按FIFO (先進先出) 排序元素,吞吐量通常要高於ArrayBlockingQueue。靜態工廠方法Executors.newFixedThreadPool()使用了這個隊列。

SynchronousQueue:一個不存儲元素的阻塞隊列。每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處於阻塞狀態,吞吐量通常要高於LinkedBlockingQueue,靜態工廠方法Executors.newCachedThreadPool使用了這個隊列。

PriorityBlockingQueue:一個具有優先級得無限阻塞隊列

maximumPoolSize(線程池最大大小):線程池允許創建的最大線程數。如果隊列滿了,並且已創建的線程數小於最大線程數,則線程池會再創建新的線程執行任務。值得注意的是如果使用了無界的任務隊列這個參數就沒什麼效果。

ThreadFactory:用於設置創建線程的工廠,可以通過線程工廠給每個創建出來的線程設置更有意義的名字,Debug和定位問題時非常又幫助

RejectedExecutionHandler(飽和策略):當隊列和線程池都滿了,說明線程池處於飽和狀態,那麼必須採取一種策略處理提交的新任務。這個策略默認情況下是AbortPolicy,表示無法處理新任務時拋出異常。以下是JDK1.5提供的四種策略。n AbortPolicy:直接拋出異常。

CallerRunsPolicy:只用調用者所在線程來運行任務。

DiscardOldestPolicy:丟棄隊列裡最近的一個任務,並執行當前任務。

DiscardPolicy:不處理,丟棄掉。

當然也可以根據應用場景需要來實現RejectedExecutionHandler接口自定義策略。如記錄日誌或持久化不能處理的任務。

keepAliveTime(線程活動保持時間):線程池的工作線程空閒後,保持存活的時間。所以如果任務很多,並且每個任務執行的時間比較短,可以調大這個時間,提高線程的利用率。

TimeUnit(線程活動保持時間的單位):可選的單位有天(DAYS),小時(HOURS),分鐘(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)

線程池的關閉:通過調用線程池的shutdown或shutdownNow方法來關閉線程池

5.java反射

參考博客 : https://www.cnblogs.com/whoislcj/p/6038511.html

6.關於java序列化反序列化的一些事

推薦博客:http://blog.csdn.net/qq_16628781/article/details/70049623

7.重寫equal()的同時也要重寫hashcode()的原因:

http://www.cnblogs.com/happyPawpaw/p/3744971.html

8.CAS操作(Compare And Swap)

關於CAS操作與ABA問題解決(博文) :

https://www.cnblogs.com/549294286/p/3766717.html

9.Java集合類

9.1)List

9.1.1)ArrayList

底層是使用對象數組實現, 使用下標遍歷更快

1)默認初始容量 : 10

2)容量擴展 : 1.5倍

9.1.2)LinkedList

底層是使用雙向鏈表實現, 使用迭代器/foreach遍歷更快

鏈表無所謂初始容量, 也不存在容量擴展

9.2)Map

9.2.1)HashMap

底層是hash數組加鏈表或者紅黑樹(jdk1.8之後, 鏈表長度大於8改用紅黑樹實現)

原理 : 通過散列函數hash函數計算出key值在hash數組中的位置, 再遍歷該位置對應的鏈表或者紅黑樹中key值所在的節點

1)關於重寫equals方法必須重寫hashcode方法, 因為必須滿足key值相等的時候hashcode必須相等, 這是重寫hashcode方法的約束

2)默認初始容量 : 16

3)默認加載因子 : 0.75(當 The next size value at which to resize (capacity * load factor), size + 1 > 容量 * 加載因子的時候)

3)hash函數 : (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

9.2.2) ConcurrentHashMap

區別於HashMap的是使用了鎖分段技術

ConcurrentHashMap的鎖分段技術:假如容器裡有多把鎖,每一把鎖用於鎖容器其中一部分數據,那麼當多線程訪問容器裡不同數據段的數據時,線程間就不會存在鎖競爭,從而可以有效的提高併發訪問效率,這就是ConcurrentHashMap所使用的鎖分段技術。首先將數據分成一段一段的存儲,然後給每一段數據配一把鎖,當一個線程佔用鎖訪問其中一個段數據的時候,其他段的數據也能被其他線程訪問。

9.2.3)TreeMap

底層使用紅黑樹實現

9.3)Set

9.3.1)HashSet

底層是HashMap

它是如何保證元素唯一性的呢?依賴的是元素的hashCode方法和euqals方法

9.3.2)TreeSet

底層是TreeMap

它的排序是如何進行的呢?通過compareTo或者compare方法中的來保證元素的唯一性.元素是以紅黑樹的形式存放的.

10.可重入鎖, 公平鎖非公平鎖

參考博文 : http://www.cnblogs.com/dolphin0520/p/3923167.html

11.volatile原理 :

JMM(java內存模型) :

Java內存模型規定所有的變量都是存在主存當中(類似於前面說的物理內存),每個線程都有自己的工作內存(類似於前面的高速緩存. 線程對變量的所有操作都必須在工作內存中進行,而不能直接對主存進行操作. 並且每個線程不能訪問其他線程的工作內存.

11.1)volatile 的做法 : 當一個共享變量被volatile修飾時,它會保證修改的值會立即被更新到主存,當有其他線程需要讀取時,它會去內存中讀取新值.

11.2)另外的做法 : 通過synchronized和Lock也能夠保證可見性,synchronized和Lock能保證同一時刻只有一個線程獲取鎖然後執行同步代碼,並且在釋放鎖之前會將對變量的修改刷新到主存當中, 因此可以保證可見性.

12.HashMap 多線程導致循環鏈

參考博文 : https://www.cnblogs.com/andy-zhou/p/5402984.html

13.HashMap中為什麼長度必須為2的冪(取餘的效率不如位運算)

所以初始化HashMap指定的容量最好是2的冪次, 避免重新計算

參考博文 : https://blog.csdn.net/zjcjava/article/details/78495416

14.HashMap多線程的Fail-Fast機制

例如 : 一個線程通過Iterator迭代器進行遍歷的時候另一個線程對Hashmap進行修改, 則會導致遍歷失敗拋出ConcurrentModificationException

參考博文 : https://www.cnblogs.com/alexlo/archive/2013/03/14/2959233.html

15.內存對其原則及其作用

1)參考博文 : https://blog.csdn.net/chy19911123/article/details/48894579

16.wait和sleep的區別

wait方法屬於Object類, sleep屬於線程類. 當線程調用Object.wait(), 當前線程會釋放出對該Object的鎖, 並等待其他線程的notify之後才能進入鎖對象等待鎖定池或者wait的時候設置時間,時間到了之後也可以進入鎖對象的等待鎖定池. 當線程調用sleep(), 調用線程進入睡眠當不會釋放鎖的佔有.

六 . 設計模式

1. 單例模式

1.1)餓漢模式

1.2)懶漢模式(使用雙重檢測, 防止併發下多個線程同時實例化)

七. Web

1.如何判斷兩次登陸為同一個用戶

1.1)單服務器中 : 使用cookie, 客戶端登錄驗證之後把狀態存放於request的session中(服務器上), 第二次請求時從request中的session查看狀態是否為登錄態. 但是並不適用於多系統服務器群(因為cookie的作用域僅僅是對應的域名)

1.2)單點登錄SSO(Single Sign On)

參考博客 : https://www.cnblogs.com/ywlaker/p/6113927.html

八. Redis

1. 關於Redis的分佈式鎖的實現 : https://wudashan.cn/2017/10/23/Redis-Distributed-Lock-Implement/

軟件工程師面試常見題目

軟件工程師面試常見題目

覺得有用就轉發分享一下吧!

看完本文有收穫?請轉發分享給更多人

關注[Java學習之樂 ]全棧開發工程師

瞭解更多知識關注【Java學習之樂】


分享到:


相關文章: