引子
人生已經如此地艱難,我卻還要找工作,我真的好難。一個工作不到兩年的渣渣要在這個時候去找工作,這是何等的無所畏懼與狂妄!年輕人,加油!
前幾天投了一些簡歷,經歷了一些筆試、面試,這裏就記錄一下自己求職的心路歷程,並且記錄一下自己在筆試、面試中碰到的題目。
題目
1、線程的六種狀態?
線程的六種狀態在 Thread.State 枚舉中定義:
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
- 當線程剛創建的時候,處於 NEW 狀態,此時線程還沒開始執行。
- 當線程的start()方法被調用後,線程開始執行任務,進入 RUNNABLE 狀態。
- 當線程在執行任務的過程中 遇到了 synchronized 同步塊,線程就會進入 BLOCKED 狀態。
- 如果線程在執行的過程中,碰到一些特殊的事件,線程就會進入 WAITING、TIMED_WAITING 狀態。比如同步塊中的對象調用 wait() 方法,那當前線程就要等待該對象調用 notify()/notifyAll()方法;通過join()方法等待的線程則會等待目標線程的終止。一旦等到了期望的事件,線程就會繼續執行,進入 RUNNABLE 狀態。
- 當線程執行完畢,進入 TERMINATED 狀態。
在有的書籍、文檔中,將這裏描述爲“線程的五種狀態”。比如,在阿里出品的《碼處高效》這本書的第七章中,就將這裏描述爲“線程的五種狀態”,如下圖:
實際上,就是將 WAITING 和 TIMED_WAITING 也劃入到了 BLOCKED 狀態中,TERMINATED 換成了 DEAD 狀態。不管怎麼分,原理都是一樣的。
2、Object.wait() 和 Thread.sleep() 的區別?
相同點:兩者都可以讓線程等待一定時間。
不同點:
- 無論是 wait()方法還是 notify() 方法,在調用前必須先獲得目標對象的一個監視器。在wait()方法執行完後,會釋放掉這個監視器。也就是說,wait()方法和notify()方法必須包含在調用對象的 synchronized 塊中。
- wait()方法可以被主動喚醒,而Thread.sleep() 只能等待時間走完。
- wait()方法會釋放掉目標對象的鎖,而Thread.sleep()不會釋放任何資源。
3、Redis持久化,RDB與AOF,聊一下?
RDB的工作方式:
默認情況下,Redis將數據集的快照保存在一個 .rdb 文件中。一般情況下,我們有三種方式開啓RDB持久化:
- SAVE命令:一般不用,原因是這是一個同步操作,在寫文件期間,服務端將阻塞客戶端的讀寫請求。
- BGSAVE命令:客戶端執行 BGSAVE命令後,服務端將會 fork() 一個子進程去進行持久化操作,父進程仍然爲客戶端服務。子進程持久化完畢後會自己退出。需要注意的是,fork() 子進程 這個操作本身仍然是同步的,如果Redis中的數據集太大,fork()操作可能也會耗時。
- 通過配置,自動持久化。我們可以通過在Redis.conf中配置,比如【SAVE 300 1】,這就表示在 300 秒內,只要有 1 次寫入操作,服務端就會自動持久化一次。其工作方式和 BGSAVE 類似。
AOF的工作方式:
每次Redis執行數據集修改的命令,都會被異步追加到AOF文件的末尾。默認情況下,AOF這種持久化方式是關閉的。
AOF有三種持久化策略:
- always:每一次寫入命令,都追加到AOF文件的末尾。
- everysec:每一秒將前一秒新增的數據追加到AOF文件的末尾。
- no:操作系統決定何時追加緩衝區的數據。
AOF日誌重寫:
有兩種方式可以進行AOF日誌重寫:
- BGREWRITEAOF命令:當客戶端執行該命令時,服務端將開啓一個AOF重寫進程,重寫一個 包含重建當前內存中數據集所需的最短命令序列 的臨時文件。
- 服務端自動重寫。這裏不多加介紹了,詳情請參閱我的另一篇專門講Redis持久化的文章。
默認情況下,只有在後臺沒有進程正在進行持久化操作時,AOF重寫纔會被觸發。
AOF日誌重寫,RDB前導:
在重寫AOF文件時,Redis能夠在AOF文件中使用RDB文件作爲前導,以便更快地重寫和恢復。
RDB和AOF的優缺點對比:
- RDB文件非常緊湊,而數據集相同的情況下,AOF文件往往更大,不利於網絡傳輸;
- 與AOF相比,在恢復一些大數據集的時候,RDB一般都會快一些;
- 根據使用的策略不同,RDB可能會丟失一小段時間的數據,AOF保存的數據往往更加完整;
- AOF文件更容易被人讀懂,而RDB則對人工閱讀不友好。
詳情參考:Redis學習筆記(一):Redis持久化——RDB與AOF
4、MySQL事務隔離級別有哪些?分別解決什麼問題?
5、JavaGC機制,簡單聊一下?
參考:《JVM學習筆記(二):JVM GC機制與垃圾收集器》
6、緩存穿透、緩存擊穿、緩存雪崩,是怎麼回事呢?如何解決這些問題?
緩存穿透:訪問一個原本不存在的Key,就會穿透緩存。流量大時,數據庫會掛掉。
解決方案:
- 布隆過濾器很好地解決了緩存穿透的問題;
- 使用key進入數據庫查詢時,即使沒有查到值,也將空值寫入數據庫;
緩存擊穿:一個存在的Key,在過期的一瞬間,大量的請求過來,這些請求都會擊穿到數據庫,造成數據庫瞬間壓力大增。
解決方案:
- 在訪問Key之前,使用 SETNX 來設置一個短期的Key來鎖定當前Key的訪問,訪問結束再刪掉該短期Key。
- 給獲取緩存的方法加鎖,這樣在高併發時大大降低了吞吐量。
- 定時刷新緩存。
緩存雪崩:大量的Key設置了同樣的過期時間,導致大量的緩存在同一時間全部過期,造成數據庫壓力瞬間增大,引起雪崩。
解決方案:
- 在給Key設置過期時間時,加上一個隨機值,使Key的過期時間分佈開來,不會集中在同一時刻失效。
總結
這公司的面試,現在就記得問了這些了。面試的問題不多,大概也就面了半個小時左右。正在整理這篇文章的時候,才發現,原來自己當時回答JVM垃圾回收算法的時候,回答的不完整,只回答了對象生存判定的兩個方式。嗯,溫故而知新~加油!
參考文檔
1、《實戰·Java高併發程序設計》第二版,葛一鳴 著,第二章。
2、《碼出高效》,孤盡、鳴沙 著,第七章。
3、https://blog.csdn.net/Zereao/article/details/99471588
4、https://blog.csdn.net/Zereao/article/details/103564297