亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Java-Mysql你所需要的面試題集內(nèi)容

OpenDigg / 1875人閱讀

摘要:注意排版不需要花花綠綠的,盡量使用語(yǔ)法。協(xié)議的長(zhǎng)連接和短連接,實(shí)質(zhì)上是協(xié)議的長(zhǎng)連接和短連接。長(zhǎng)連接短連接究竟是什么三次握手和四次揮手面試??蜑榱藴?zhǔn)確無(wú)誤地把數(shù)據(jù)送達(dá)目標(biāo)處,協(xié)議采用了三次握手策略。

一 簡(jiǎn)歷該如何寫(xiě)

1.1 為什么說(shuō)簡(jiǎn)歷很重要?
1.2-這3點(diǎn)你必須知道
1.3-兩大法則了解一
1.4-項(xiàng)目經(jīng)歷怎么寫(xiě)?
1.5-專業(yè)技能該怎么寫(xiě)?
1.6-開(kāi)源程序員簡(jiǎn)歷模板分享
1.7 其他的一些小tips

二 計(jì)算機(jī)網(wǎng)絡(luò)常見(jiàn)面試點(diǎn)總結(jié)

計(jì)算機(jī)網(wǎng)絡(luò)常見(jiàn)問(wèn)題回顧
2.1 TCP、UDP 協(xié)議的區(qū)別
2.2 在瀏覽器中輸入url地址 ->> 顯示主頁(yè)的過(guò)程
2.3 各種協(xié)議與HTTP協(xié)議之間的關(guān)系
2.4 HTTP長(zhǎng)連接、短連接
2.5 TCP 三次握手和四次揮手

三 Linux

3.1-簡(jiǎn)單介紹一下-linux-文件系統(tǒng)?
3.2 一些常見(jiàn)的 Linux 命令了解嗎?

四 MySQL

4.1 說(shuō)說(shuō)自己對(duì)于 MySQL 常見(jiàn)的兩種存儲(chǔ)引擎:MyISAM與InnoDB的理解
4.2 數(shù)據(jù)庫(kù)索引了解嗎?
4.3 對(duì)于大表的常見(jiàn)優(yōu)化手段說(shuō)一下

五 Redis

5.1 redis 簡(jiǎn)介
5.2 為什么要用 redis /為什么要用緩存
5.3 為什么要用 redis 而不用 map/guava 做緩存?
5.4 redis 和 memcached 的區(qū)別
5.5 redis 常見(jiàn)數(shù)據(jù)結(jié)構(gòu)以及使用場(chǎng)景分析
5.6 redis 設(shè)置過(guò)期時(shí)間
5.7 redis 內(nèi)存淘汰機(jī)制
5.8 redis 持久化機(jī)制(怎么保證 redis 掛掉之后再重啟數(shù)據(jù)可以進(jìn)行恢復(fù))
5.9 緩存雪崩和緩存穿透問(wèn)題解決方案
5.10 如何解決 Redis 的并發(fā)競(jìng)爭(zhēng) Key 問(wèn)題
5.11 如何保證緩存與數(shù)據(jù)庫(kù)雙寫(xiě)時(shí)的數(shù)據(jù)一致性?

六 Java

6.1 Java 基礎(chǔ)知識(shí)
6.2 Java 集合框架
6.3 Java多線程
6.4 Java虛擬機(jī)
6.5 設(shè)計(jì)模式

七 數(shù)據(jù)結(jié)構(gòu)
八 算法
九 Spring

9.1 Spring Bean 的作用域
9.2 Spring 事務(wù)中的隔離級(jí)別
9.3 Spring 事務(wù)中的事務(wù)傳播行為
9.4 AOP
9.5 IOC

十 實(shí)際場(chǎng)景題
寫(xiě)在最后

前言
不論是校招還是社招都避免不了各種面試、筆試,如何去準(zhǔn)備這些東西就顯得格外重要。不論是筆試還是面試都是有章可循的,我這個(gè)“有章可循”說(shuō)的意思只是說(shuō)應(yīng)對(duì)技術(shù)面試是可以提前準(zhǔn)備。 我其實(shí)特別不喜歡那種臨近考試就提前背啊記啊各種題的行為,非常反對(duì)!我覺(jué)得這種方法特別極端,而且在稍有一點(diǎn)經(jīng)驗(yàn)的面試官面前是根本沒(méi)有用的。建議大家還是一步一個(gè)腳印踏踏實(shí)實(shí)地走。
運(yùn)籌帷幄之后,決勝千里之外!不打毫無(wú)準(zhǔn)備的仗,我覺(jué)得大家可以先從下面幾個(gè)方面來(lái)準(zhǔn)備面試:

自我介紹。(你可千萬(wàn)這樣介紹:“我叫某某,性別,來(lái)自哪里,學(xué)校是那個(gè),自己愛(ài)干什么”,記?。憾嗾f(shuō)點(diǎn)簡(jiǎn)歷上沒(méi)有的,多說(shuō)點(diǎn)自己哪里比別人強(qiáng)?。?br>自己面試中可能涉及哪些知識(shí)點(diǎn)、那些知識(shí)點(diǎn)是重點(diǎn)。
面試中哪些問(wèn)題會(huì)被經(jīng)常問(wèn)到、面試中自己改如何回答。(強(qiáng)烈不推薦背題,第一:通過(guò)背這種方式你能記住多少?能記住多久?第二:背題的方式的學(xué)習(xí)很難堅(jiān)持下去!)
自己的簡(jiǎn)歷該如何寫(xiě)。

“80%的offer掌握在20%的人手中” 這句話也不是不無(wú)道理的。決定你面試能否成功的因素中實(shí)力固然占有很大一部分比例,但是如果你的心態(tài)或者說(shuō)運(yùn)氣不好的話,依然無(wú)法拿到滿意的 offer。運(yùn)氣暫且不談,就拿心態(tài)來(lái)說(shuō),千萬(wàn)不要因?yàn)槊嬖囀《鴼怵H或者說(shuō)懷疑自己的能力,面試失敗之后多總結(jié)一下失敗的原因,后面你就會(huì)發(fā)現(xiàn)自己會(huì)越來(lái)越強(qiáng)大。
另外,大家要明確的很重要的幾點(diǎn)是:

寫(xiě)在簡(jiǎn)歷上的東西一定要慎重,這可能是面試官大量提問(wèn)的地方;
大部分應(yīng)屆生找工作的硬傷是沒(méi)有工作經(jīng)驗(yàn)或?qū)嵙?xí)經(jīng)歷;
將自己的項(xiàng)目經(jīng)歷完美的展示出來(lái)非常重要。

一 簡(jiǎn)歷該如何寫(xiě)

俗話說(shuō)的好:“工欲善其事,必先利其器”。準(zhǔn)備一份好的簡(jiǎn)歷對(duì)于能不能找到一份好工作起到了至關(guān)重要的作用。

1.1 為什么說(shuō)簡(jiǎn)歷很重要?
假如你是網(wǎng)申,你的簡(jiǎn)歷必然會(huì)經(jīng)過(guò)HR的篩選,一張簡(jiǎn)歷HR可能也就花費(fèi)10秒鐘看一下,然后HR就會(huì)決定你這一關(guān)是Fail還是Pass。
假如你是內(nèi)推,如果你的簡(jiǎn)歷沒(méi)有什么優(yōu)勢(shì)的話,就算是內(nèi)推你的人再用心,也無(wú)能為力。
另外,就算你通過(guò)了篩選,后面的面試中,面試官也會(huì)根據(jù)你的簡(jiǎn)歷來(lái)判斷你究竟是否值得他花費(fèi)很多時(shí)間去面試。
1.2 這3點(diǎn)你必須知道

大部分應(yīng)屆生找工作的硬傷是沒(méi)有工作經(jīng)驗(yàn)或?qū)嵙?xí)經(jīng)歷;
寫(xiě)在簡(jiǎn)歷上的東西一定要慎重,這可能是面試官大量提問(wèn)的地方;
將自己的項(xiàng)目經(jīng)歷完美的展示出來(lái)非常重要。

1.3 兩大法則了解一下
目前寫(xiě)簡(jiǎn)歷的方式有兩種普遍被認(rèn)可,一種是 STAR, 一種是 FAB。
STAR法則(Situation Task Action Result):

Situation: 事情是在什么情況下發(fā)生;
Task:: 你是如何明確你的任務(wù)的;
Action: 針對(duì)這樣的情況分析,你采用了什么行動(dòng)方式;
Result: 結(jié)果怎樣,在這樣的情況下你學(xué)習(xí)到了什么。

FAB 法則(Feature Advantage Benefit):

Feature: 是什么;
Advantage: 比別人好在哪些地方;
Benefit: 如果雇傭你,招聘方會(huì)得到什么好處。

1.4 項(xiàng)目經(jīng)歷怎么寫(xiě)?
簡(jiǎn)歷上有一兩個(gè)項(xiàng)目經(jīng)歷很正常,但是真正能把項(xiàng)目經(jīng)歷很好的展示給面試官的非常少。對(duì)于項(xiàng)目經(jīng)歷大家可以考慮從如下幾點(diǎn)來(lái)寫(xiě):

對(duì)項(xiàng)目整體設(shè)計(jì)的一個(gè)感受
在這個(gè)項(xiàng)目中你負(fù)責(zé)了什么、做了什么、擔(dān)任了什么角色
從這個(gè)項(xiàng)目中你學(xué)會(huì)了那些東西,使用到了那些技術(shù),學(xué)會(huì)了那些新技術(shù)的使用
另外項(xiàng)目描述中,最好可以體現(xiàn)自己的綜合素質(zhì),比如你是如何協(xié)調(diào)項(xiàng)目組成員協(xié)同開(kāi)發(fā)的或者在遇到某一個(gè)棘手的問(wèn)題的時(shí)候你是如何解決的。

1.5 專業(yè)技能該怎么寫(xiě)?
先問(wèn)一下你自己會(huì)什么,然后看看你意向的公司需要什么。一般HR可能并不太懂技術(shù),所以他在篩選簡(jiǎn)歷的時(shí)候可能就盯著你專業(yè)技能的關(guān)鍵詞來(lái)看。對(duì)于公司有要求而你不會(huì)的技能,你可以花幾天時(shí)間學(xué)習(xí)一下,然后在簡(jiǎn)歷上可以寫(xiě)上自己了解這個(gè)技能。比如你可以這樣寫(xiě):

Dubbo:精通
Spring:精通
Docker:掌握
SOA分布式開(kāi)發(fā) :掌握
Spring Cloud:了解

1.7 其他的一些小tips

盡量避免主觀表述,少一點(diǎn)語(yǔ)義模糊的形容詞,盡量要簡(jiǎn)潔明了,邏輯結(jié)構(gòu)清晰。
注意排版(不需要花花綠綠的),盡量使用Markdown語(yǔ)法。
如果自己有博客或者個(gè)人技術(shù)棧點(diǎn)的話,寫(xiě)上去會(huì)為你加分很多。
如果自己的Github比較活躍的話,寫(xiě)上去也會(huì)為你加分很多。
注意簡(jiǎn)歷真實(shí)性,一定不要寫(xiě)自己不會(huì)的東西,或者帶有欺騙性的內(nèi)容
項(xiàng)目經(jīng)歷建議以時(shí)間倒序排序,另外項(xiàng)目經(jīng)歷不在于多,而在于有亮點(diǎn)。
如果內(nèi)容過(guò)多的話,不需要非把內(nèi)容壓縮到一頁(yè),保持排版干凈整潔就可以了。
簡(jiǎn)歷最后最好能加上:“感謝您花時(shí)間閱讀我的簡(jiǎn)歷,期待能有機(jī)會(huì)和您共事?!边@句話,顯的你會(huì)很有禮貌。

二 計(jì)算機(jī)網(wǎng)絡(luò)常見(jiàn)面試點(diǎn)總結(jié)

計(jì)算機(jī)網(wǎng)絡(luò)常見(jiàn)問(wèn)題回顧

TCP三次握手和四次揮手、
在瀏覽器中輸入url地址->>顯示主頁(yè)的過(guò)程
TCP 協(xié)議如何保證可靠傳輸
HTTP和HTTPS的區(qū)別
TCP、UDP協(xié)議的區(qū)別
常見(jiàn)的狀態(tài)碼。

下面列舉幾個(gè)常見(jiàn)問(wèn)題的回答!
2.1 TCP、UDP 協(xié)議的區(qū)別

UDP 在傳送數(shù)據(jù)之前不需要先建立連接,遠(yuǎn)地主機(jī)在收到 UDP 報(bào)文后,不需要給出任何確認(rèn)。雖然 UDP 不提供可靠交付,但在某些情況下 UDP 確是一種最有效的工作方式(一般用于即時(shí)通信),比如: QQ 語(yǔ)音、 QQ 視頻 、直播等等
TCP 提供面向連接的服務(wù)。在傳送數(shù)據(jù)之前必須先建立連接,數(shù)據(jù)傳送結(jié)束后要釋放連接。 TCP 不提供廣播或多播服務(wù)。由于 TCP 要提供可靠的,面向連接的運(yùn)輸服務(wù)(TCP的可靠體現(xiàn)在TCP在傳遞數(shù)據(jù)之前,會(huì)有三次握手來(lái)建立連接,而且在數(shù)據(jù)傳遞時(shí),有確認(rèn)、窗口、重傳、擁塞控制機(jī)制,在數(shù)據(jù)傳完后,還會(huì)斷開(kāi)連接用來(lái)節(jié)約系統(tǒng)資源),這一難以避免增加了許多開(kāi)銷,如確認(rèn),流量控制,計(jì)時(shí)器以及連接管理等。這不僅使協(xié)議數(shù)據(jù)單元的首部增大很多,還要占用許多處理機(jī)資源。TCP 一般用于文件傳輸、發(fā)送和接收郵件、遠(yuǎn)程登錄等場(chǎng)景。
2.2 在瀏覽器中輸入url地址 ->> 顯示主頁(yè)的過(guò)程
百度好像最喜歡問(wèn)這個(gè)問(wèn)題。

打開(kāi)一個(gè)網(wǎng)頁(yè),整個(gè)過(guò)程會(huì)使用哪些協(xié)議

總體來(lái)說(shuō)分為以下幾個(gè)過(guò)程:

DNS解析
TCP連接
發(fā)送HTTP請(qǐng)求
服務(wù)器處理請(qǐng)求并返回HTTP報(bào)文
瀏覽器解析渲染頁(yè)面
連接結(jié)束

2.3 各種協(xié)議與HTTP協(xié)議之間的關(guān)系
一般面試官會(huì)通過(guò)這樣的問(wèn)題來(lái)考察你對(duì)計(jì)算機(jī)網(wǎng)絡(luò)知識(shí)體系的理解。

2.4 HTTP長(zhǎng)連接、短連接
在HTTP/1.0中默認(rèn)使用短連接。也就是說(shuō),客戶端和服務(wù)器每進(jìn)行一次HTTP操作,就建立一次連接,任務(wù)結(jié)束就中斷連接。當(dāng)客戶端瀏覽器訪問(wèn)的某個(gè)HTML或其他類型的Web頁(yè)中包含有其他的Web資源(如JavaScript文件、圖像文件、CSS文件等),每遇到這樣一個(gè)Web資源,瀏覽器就會(huì)重新建立一個(gè)HTTP會(huì)話。
而從HTTP/1.1起,默認(rèn)使用長(zhǎng)連接,用以保持連接特性。使用長(zhǎng)連接的HTTP協(xié)議,會(huì)在響應(yīng)頭加入這行代碼:
Connection:keep-alive
復(fù)制代碼在使用長(zhǎng)連接的情況下,當(dāng)一個(gè)網(wǎng)頁(yè)打開(kāi)完成后,客戶端和服務(wù)器之間用于傳輸HTTP數(shù)據(jù)的TCP連接不會(huì)關(guān)閉,客戶端再次訪問(wèn)這個(gè)服務(wù)器時(shí),會(huì)繼續(xù)使用這一條已經(jīng)建立的連接。Keep-Alive不會(huì)永久保持連接,它有一個(gè)保持時(shí)間,可以在不同的服務(wù)器軟件(如Apache)中設(shè)定這個(gè)時(shí)間。實(shí)現(xiàn)長(zhǎng)連接需要客戶端和服務(wù)端都支持長(zhǎng)連接。
HTTP協(xié)議的長(zhǎng)連接和短連接,實(shí)質(zhì)上是TCP協(xié)議的長(zhǎng)連接和短連接。
—— 《HTTP長(zhǎng)連接、短連接究竟是什么?》
2.5 TCP 三次握手和四次揮手(面試???
為了準(zhǔn)確無(wú)誤地把數(shù)據(jù)送達(dá)目標(biāo)處,TCP協(xié)議采用了三次握手策略。

客戶端–發(fā)送帶有 SYN 標(biāo)志的數(shù)據(jù)包–一次握手–服務(wù)端
服務(wù)端–發(fā)送帶有 SYN/ACK 標(biāo)志的數(shù)據(jù)包–二次握手–客戶端
客戶端–發(fā)送帶有帶有 ACK 標(biāo)志的數(shù)據(jù)包–三次握手–服務(wù)端

為什么要三次握手?

三次握手的目的是建立可靠的通信信道,說(shuō)到通訊,簡(jiǎn)單來(lái)說(shuō)就是數(shù)據(jù)的發(fā)送與接收,而三次握手最主要的目的就是雙方確認(rèn)自己與對(duì)方的發(fā)送與接收是正常的。
第一次握手:Client 什么都不能確認(rèn);Server 確認(rèn)了對(duì)方發(fā)送正常
第二次握手:Client 確認(rèn)了:自己發(fā)送、接收正常,對(duì)方發(fā)送、接收正常;Server 確認(rèn)了:自己接收正常,對(duì)方發(fā)送正常
第三次握手:Client 確認(rèn)了:自己發(fā)送、接收正常,對(duì)方發(fā)送、接收正常;Server 確認(rèn)了:自己發(fā)送、接收正常,對(duì)方發(fā)送接收正常
所以三次握手就能確認(rèn)雙發(fā)收發(fā)功能都正常,缺一不可。

為什么要傳回 SYN

接收端傳回發(fā)送端所發(fā)送的 SYN 是為了告訴發(fā)送端,我接收到的信息確實(shí)就是你所發(fā)送的信號(hào)了。

SYN 是 TCP/IP 建立連接時(shí)使用的握手信號(hào)。在客戶機(jī)和服務(wù)器之間建立正常的 TCP 網(wǎng)絡(luò)連接時(shí),客戶機(jī)首先發(fā)出一個(gè) SYN 消息,服務(wù)器使用 SYN-ACK 應(yīng)答表示接收到了這個(gè)消息,最后客戶機(jī)再以 ACK(Acknowledgement[漢譯:確認(rèn)字符 ,在數(shù)據(jù)通信傳輸中,接收站發(fā)給發(fā)送站的一種傳輸控制字符。它表示確認(rèn)發(fā)來(lái)的數(shù)據(jù)已經(jīng)接受無(wú)誤。 ])消息響應(yīng)。這樣在客戶機(jī)和服務(wù)器之間才能建立起可靠的TCP連接,數(shù)據(jù)才可以在客戶機(jī)和服務(wù)器之間傳遞。

傳了 SYN,為啥還要傳 ACK

雙方通信無(wú)誤必須是兩者互相發(fā)送信息都無(wú)誤。傳了 SYN,證明發(fā)送方到接收方的通道沒(méi)有問(wèn)題,但是接收方到發(fā)送方的通道還需要 ACK 信號(hào)來(lái)進(jìn)行驗(yàn)證。

斷開(kāi)一個(gè) TCP 連接則需要“四次揮手”:

客戶端-發(fā)送一個(gè) FIN,用來(lái)關(guān)閉客戶端到服務(wù)器的數(shù)據(jù)傳送
服務(wù)器-收到這個(gè) FIN,它發(fā)回一 個(gè) ACK,確認(rèn)序號(hào)為收到的序號(hào)加1 。和 SYN 一樣,一個(gè) FIN 將占用一個(gè)序號(hào)
服務(wù)器-關(guān)閉與客戶端的連接,發(fā)送一個(gè)FIN給客戶端
客戶端-發(fā)回 ACK 報(bào)文確認(rèn),并將確認(rèn)序號(hào)設(shè)置為收到序號(hào)加1

為什么要四次揮手

任何一方都可以在數(shù)據(jù)傳送結(jié)束后發(fā)出連接釋放的通知,待對(duì)方確認(rèn)后進(jìn)入半關(guān)閉狀態(tài)。當(dāng)另一方也沒(méi)有數(shù)據(jù)再發(fā)送的時(shí)候,則發(fā)出連接釋放通知,對(duì)方確認(rèn)后就完全關(guān)閉了TCP連接。
舉個(gè)例子:A 和 B 打電話,通話即將結(jié)束后,A 說(shuō)“我沒(méi)啥要說(shuō)的了”,B回答“我知道了”,但是 B 可能還會(huì)有要說(shuō)的話,A 不能要求 B 跟著自己的節(jié)奏結(jié)束通話,于是 B 可能又巴拉巴拉說(shuō)了一通,最后 B 說(shuō)“我說(shuō)完了”,A 回答“知道了”,這樣通話才算結(jié)束。

三 Linux

3.1 簡(jiǎn)單介紹一下 Linux 文件系統(tǒng)?

Linux文件系統(tǒng)簡(jiǎn)介

在Linux操作系統(tǒng)中,所有被操作系統(tǒng)管理的資源,例如網(wǎng)絡(luò)接口卡、磁盤(pán)驅(qū)動(dòng)器、打印機(jī)、輸入輸出設(shè)備、普通文件或是目錄都被看作是一個(gè)文件。
也就是說(shuō)在LINUX系統(tǒng)中有一個(gè)重要的概念:一切都是文件。其實(shí)這是UNIX哲學(xué)的一個(gè)體現(xiàn),而Linux是重寫(xiě)UNIX而來(lái),所以這個(gè)概念也就傳承了下來(lái)。在UNIX系統(tǒng)中,把一切資源都看作是文件,包括硬件設(shè)備。UNIX系統(tǒng)把每個(gè)硬件都看成是一個(gè)文件,通常稱為設(shè)備文件,這樣用戶就可以用讀寫(xiě)文件的方式實(shí)現(xiàn)對(duì)硬件的訪問(wèn)。

文件類型與目錄結(jié)構(gòu)

Linux支持5種文件類型 :

Linux的目錄結(jié)構(gòu)如下:
Linux文件系統(tǒng)的結(jié)構(gòu)層次鮮明,就像一棵倒立的樹(shù),最頂層是其根目錄:

常見(jiàn)目錄說(shuō)明:

/bin: 存放二進(jìn)制可執(zhí)行文件(ls,cat,mkdir等),常用命令一般都在這里;
/etc: 存放系統(tǒng)管理和配置文件;
/home: 存放所有用戶文件的根目錄,是用戶主目錄的基點(diǎn),比如用戶user的主目錄就是/home/user,可以用~user表示;
/usr : 用于存放系統(tǒng)應(yīng)用程序;
/opt: 額外安裝的可選應(yīng)用程序包所放置的位置。一般情況下,我們可以把tomcat等都安裝到這里;
/proc: 虛擬文件系統(tǒng)目錄,是系統(tǒng)內(nèi)存的映射。可直接訪問(wèn)這個(gè)目錄來(lái)獲取系統(tǒng)信息;
/root: 超級(jí)用戶(系統(tǒng)管理員)的主目錄(特權(quán)階級(jí)^o^);
/sbin: 存放二進(jìn)制可執(zhí)行文件,只有root才能訪問(wèn)。這里存放的是系統(tǒng)管理員使用的系統(tǒng)級(jí)別的管理命令和程序。如ifconfig等;
/dev: 用于存放設(shè)備文件;
/mnt: 系統(tǒng)管理員安裝臨時(shí)文件系統(tǒng)的安裝點(diǎn),系統(tǒng)提供這個(gè)目錄是讓用戶臨時(shí)掛載其他的文件系統(tǒng);
/boot: 存放用于系統(tǒng)引導(dǎo)時(shí)使用的各種文件;
/lib : 存放著和系統(tǒng)運(yùn)行相關(guān)的庫(kù)文件 ;
/tmp: 用于存放各種臨時(shí)文件,是公用的臨時(shí)文件存儲(chǔ)點(diǎn);
/var: 用于存放運(yùn)行時(shí)需要改變數(shù)據(jù)的文件,也是某些大文件的溢出區(qū),比方說(shuō)各種服務(wù)的日志文件(系統(tǒng)啟動(dòng)日志等。)等;
/lost+found: 這個(gè)目錄平時(shí)是空的,系統(tǒng)非正常關(guān)機(jī)而留下“無(wú)家可歸”的文件(windows下叫什么.chk)就在這里。

3.2 一些常見(jiàn)的 Linux 命令了解嗎?

目錄切換命令

cd usr: 切換到該目錄下usr目錄
cd ..(或cd../): 切換到上一層目錄
cd /: 切換到系統(tǒng)根目錄
cd ~: 切換到用戶主目錄
cd -: 切換到上一個(gè)所在目錄

目錄的操作命令(增刪改查)

mkdir 目錄名稱: 增加目錄

ls或者ll(ll是ls -l的縮寫(xiě),ll命令以看到該目錄下的所有目錄和文件的詳細(xì)信息):查看目錄信息

find 目錄 參數(shù): 尋找目錄(查)

mv 目錄名稱 新目錄名稱: 修改目錄的名稱(改)
注意:mv的語(yǔ)法不僅可以對(duì)目錄進(jìn)行重命名而且也可以對(duì)各種文件,壓縮包等進(jìn)行 重命名的操作。mv命令用來(lái)對(duì)文件或目錄重新命名,或者將文件從一個(gè)目錄移到另一個(gè)目錄中。后面會(huì)介紹到mv命令的另一個(gè)用法。

mv 目錄名稱 目錄的新位置: 移動(dòng)目錄的位置---剪切(改)
注意:mv語(yǔ)法不僅可以對(duì)目錄進(jìn)行剪切操作,對(duì)文件和壓縮包等都可執(zhí)行剪切操作。另外mv與cp的結(jié)果不同,mv好像文件“搬家”,文件個(gè)數(shù)并未增加。而cp對(duì)文件進(jìn)行復(fù)制,文件個(gè)數(shù)增加了。

cp -r 目錄名稱 目錄拷貝的目標(biāo)位置: 拷貝目錄(改),-r代表遞歸拷貝
注意:cp命令不僅可以拷貝目錄還可以拷貝文件,壓縮包等,拷貝文件和壓縮包時(shí)不 用寫(xiě)-r遞歸

rm [-rf] 目錄: 刪除目錄(刪)
注意:rm不僅可以刪除目錄,也可以刪除其他文件或壓縮包,為了增強(qiáng)大家的記憶, 無(wú)論刪除任何目錄或文件,都直接使用rm -rf 目錄/文件/壓縮包

文件的操作命令(增刪改查)

touch 文件名稱: 文件的創(chuàng)建(增)

cat/more/less/tail 文件名稱 文件的查看(查)

cat: 只能顯示最后一屏內(nèi)容
more: 可以顯示百分比,回車可以向下一行, 空格可以向下一頁(yè),q可以退出查看
less: 可以使用鍵盤(pán)上的PgUp和PgDn向上 和向下翻頁(yè),q結(jié)束查看
tail-10 : 查看文件的后10行,Ctrl+C結(jié)束

注意:命令 tail -f 文件 可以對(duì)某個(gè)文件進(jìn)行動(dòng)態(tài)監(jiān)控,例如tomcat的日志文件, 會(huì)隨著程序的運(yùn)行,日志會(huì)變化,可以使用tail -f catalina-2016-11-11.log 監(jiān)控 文 件的變化

vim 文件: 修改文件的內(nèi)容(改)
vim編輯器是Linux中的強(qiáng)大組件,是vi編輯器的加強(qiáng)版,vim編輯器的命令和快捷方式有很多,但此處不一一闡述,大家也無(wú)需研究的很透徹,使用vim編輯修改文件的方式基本會(huì)使用就可以了。
在實(shí)際開(kāi)發(fā)中,使用vim編輯器主要作用就是修改配置文件,下面是一般步驟:
vim 文件------>進(jìn)入文件----->命令模式------>按i進(jìn)入編輯模式----->編輯文件 ------->按Esc進(jìn)入底行模式----->輸入:wq/q! (輸入wq代表寫(xiě)入內(nèi)容并退出,即保存;輸入q!代表強(qiáng)制退出不保存。)

rm -rf 文件: 刪除文件(刪)
同目錄刪除:熟記 rm -rf 文件 即可

壓縮文件的操作命令

1)打包并壓縮文件:
Linux中的打包文件一般是以.tar結(jié)尾的,壓縮的命令一般是以.gz結(jié)尾的。
而一般情況下打包和壓縮是一起進(jìn)行的,打包并壓縮后的文件的后綴名一般.tar.gz。
命令:tar -zcvf 打包壓縮后的文件名 要打包壓縮的文件
其中:
z:調(diào)用gzip壓縮命令進(jìn)行壓縮
c:打包文件
v:顯示運(yùn)行過(guò)程
f:指定文件名
比如:加入test目錄下有三個(gè)文件分別是 :aaa.txt bbb.txt ccc.txt,如果我們要打包test目錄并指定壓縮后的壓縮包名稱為test.tar.gz可以使用命令:tar -zcvf test.tar.gz aaa.txt bbb.txt ccc.txt或:tar -zcvf test.tar.gz /test/
2)解壓壓縮包:
命令:tar [-xvf] 壓縮文件
其中:x:代表解壓
示例:
1 將/test下的test.tar.gz解壓到當(dāng)前目錄下可以使用命令:tar -xvf test.tar.gz
2 將/test下的test.tar.gz解壓到根目錄/usr下:tar -xvf xxx.tar.gz -C /usr(- C代表指定解壓的位置)

其他常用命令

pwd: 顯示當(dāng)前所在位置

grep 要搜索的字符串 要搜索的文件 --color: 搜索命令,--color代表高亮顯示

ps -ef/ps aux: 這兩個(gè)命令都是查看當(dāng)前系統(tǒng)正在運(yùn)行進(jìn)程,兩者的區(qū)別是展示格式不同。如果想要查看特定的進(jìn)程可以使用這樣的格式:ps aux|grep redis (查看包括redis字符串的進(jìn)程)
注意:如果直接用ps((Process Status))命令,會(huì)顯示所有進(jìn)程的狀態(tài),通常結(jié)合grep命令查看某進(jìn)程的狀態(tài)。

kill -9 進(jìn)程的pid: 殺死進(jìn)程(-9 表示強(qiáng)制終止。)
先用ps查找進(jìn)程,然后用kill殺掉

網(wǎng)絡(luò)通信命令:

查看當(dāng)前系統(tǒng)的網(wǎng)卡信息:ifconfig
查看與某臺(tái)機(jī)器的連接情況:ping
查看當(dāng)前系統(tǒng)的端口使用:netstat -an

shutdown: shutdown -h now: 指定現(xiàn)在立即關(guān)機(jī);shutdown +5 "System will shutdown after 5 minutes":指定5分鐘后關(guān)機(jī),同時(shí)送出警告信息給登入用戶。

reboot: reboot: 重開(kāi)機(jī)。reboot -w: 做個(gè)重開(kāi)機(jī)的模擬(只有紀(jì)錄并不會(huì)真的重開(kāi)機(jī))。

四 MySQL

4.1 說(shuō)說(shuō)自己對(duì)于 MySQL 常見(jiàn)的兩種存儲(chǔ)引擎:MyISAM與InnoDB的理解
關(guān)于二者的對(duì)比與總結(jié):

count運(yùn)算上的區(qū)別:因?yàn)镸yISAM緩存有表meta-data(行數(shù)等),因此在做COUNT(*)時(shí)對(duì)于一個(gè)結(jié)構(gòu)很好的查詢是不需要消耗多少資源的。而對(duì)于InnoDB來(lái)說(shuō),則沒(méi)有這種緩存。
是否支持事務(wù)和崩潰后的安全恢復(fù): MyISAM 強(qiáng)調(diào)的是性能,每次查詢具有原子性,其執(zhí)行數(shù)度比InnoDB類型更快,但是不提供事務(wù)支持。但是InnoDB 提供事務(wù)支持事務(wù),外部鍵等高級(jí)數(shù)據(jù)庫(kù)功能。 具有事務(wù)(commit)、回滾(rollback)和崩潰修復(fù)能力(crash recovery capabilities)的事務(wù)安全(transaction-safe (ACID compliant))型表。
是否支持外鍵: MyISAM不支持,而InnoDB支持。

MyISAM更適合讀密集的表,而InnoDB更適合寫(xiě)密集的的表。 在數(shù)據(jù)庫(kù)做主從分離的情況下,經(jīng)常選擇MyISAM作為主庫(kù)的存儲(chǔ)引擎。
一般來(lái)說(shuō),如果需要事務(wù)支持,并且有較高的并發(fā)讀取頻率(MyISAM的表鎖的粒度太大,所以當(dāng)該表寫(xiě)并發(fā)量較高時(shí),要等待的查詢就會(huì)很多了),InnoDB是不錯(cuò)的選擇。如果你的數(shù)據(jù)量很大(MyISAM支持壓縮特性可以減少磁盤(pán)的空間占用),而且不需要支持事務(wù)時(shí),MyISAM是最好的選擇。
4.2 數(shù)據(jù)庫(kù)索引了解嗎?
Mysql索引使用的數(shù)據(jù)結(jié)構(gòu)主要有BTree索引 和 哈希索引 。對(duì)于哈希索引來(lái)說(shuō),底層的數(shù)據(jù)結(jié)構(gòu)就是哈希表,因此在絕大多數(shù)需求為單條記錄查詢的時(shí)候,可以選擇哈希索引,查詢性能最快;其余大部分場(chǎng)景,建議選擇BTree索引。
Mysql的BTree索引使用的是B數(shù)中的B+Tree,但對(duì)于主要的兩種存儲(chǔ)引擎的實(shí)現(xiàn)方式是不同的。

MyISAM: B+Tree葉節(jié)點(diǎn)的data域存放的是數(shù)據(jù)記錄的地址。在索引檢索的時(shí)候,首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,則取出其 data 域的值,然后以 data 域的值為地址讀取相應(yīng)的數(shù)據(jù)記錄。這被稱為“非聚簇索引”。
InnoDB: 其數(shù)據(jù)文件本身就是索引文件。相比MyISAM,索引文件和數(shù)據(jù)文件是分離的,其表數(shù)據(jù)文件本身就是按B+Tree組織的一個(gè)索引結(jié)構(gòu),樹(shù)的葉節(jié)點(diǎn)data域保存了完整的數(shù)據(jù)記錄。這個(gè)索引的key是數(shù)據(jù)表的主鍵,因此InnoDB表數(shù)據(jù)文件本身就是主索引。這被稱為“聚簇索引(或聚集索引)”。而其余的索引都作為輔助索引(非聚集索引),輔助索引的data域存儲(chǔ)相應(yīng)記錄主鍵的值而不是地址,這也是和MyISAM不同的地方。在根據(jù)主索引搜索時(shí),直接找到key所在的節(jié)點(diǎn)即可取出數(shù)據(jù);在根據(jù)輔助索引查找時(shí),則需要先取出主鍵的值,在走一遍主索引。 因此,在設(shè)計(jì)表的時(shí)候,不建議使用過(guò)長(zhǎng)的字段作為主鍵,也不建議使用非單調(diào)的字段作為主鍵,這樣會(huì)造成主索引頻繁分裂。 PS:整理自《Java工程師修煉之道》

4.3 對(duì)于大表的常見(jiàn)優(yōu)化手段說(shuō)一下
當(dāng)MySQL單表記錄數(shù)過(guò)大時(shí),數(shù)據(jù)庫(kù)的CRUD性能會(huì)明顯下降,一些常見(jiàn)的優(yōu)化措施如下:

限定數(shù)據(jù)的范圍: 務(wù)必禁止不帶任何限制數(shù)據(jù)范圍條件的查詢語(yǔ)句。比如:我們當(dāng)用戶在查詢訂單歷史的時(shí)候,我們可以控制在一個(gè)月的范圍內(nèi)。;

讀/寫(xiě)分離: 經(jīng)典的數(shù)據(jù)庫(kù)拆分方案,主庫(kù)負(fù)責(zé)寫(xiě),從庫(kù)負(fù)責(zé)讀;

緩存: 使用MySQL的緩存,另外對(duì)重量級(jí)、更新少的數(shù)據(jù)可以考慮使用應(yīng)用級(jí)別的緩存;

垂直分區(qū):
根據(jù)數(shù)據(jù)庫(kù)里面數(shù)據(jù)表的相關(guān)性進(jìn)行拆分。 例如,用戶表中既有用戶的登錄信息又有用戶的基本信息,可以將用戶表拆分成兩個(gè)多帶帶的表,甚至放到多帶帶的庫(kù)做分庫(kù)。
簡(jiǎn)單來(lái)說(shuō)垂直拆分是指數(shù)據(jù)表列的拆分,把一張列比較多的表拆分為多張表。 如下圖所示,這樣來(lái)說(shuō)大家應(yīng)該就更容易理解了。

垂直拆分的優(yōu)點(diǎn): 可以使得行數(shù)據(jù)變小,在查詢時(shí)減少讀取的Block數(shù),減少I/O次數(shù)。此外,垂直分區(qū)可以簡(jiǎn)化表的結(jié)構(gòu),易于維護(hù)。
垂直拆分的缺點(diǎn): 主鍵會(huì)出現(xiàn)冗余,需要管理冗余列,并會(huì)引起Join操作,可以通過(guò)在應(yīng)用層進(jìn)行Join來(lái)解決。此外,垂直分區(qū)會(huì)讓事務(wù)變得更加復(fù)雜;

水平分區(qū):
保持?jǐn)?shù)據(jù)表結(jié)構(gòu)不變,通過(guò)某種策略存儲(chǔ)數(shù)據(jù)分片。這樣每一片數(shù)據(jù)分散到不同的表或者庫(kù)中,達(dá)到了分布式的目的。 水平拆分可以支撐非常大的數(shù)據(jù)量。
水平拆分是指數(shù)據(jù)表行的拆分,表的行數(shù)超過(guò)200萬(wàn)行時(shí),就會(huì)變慢,這時(shí)可以把一張的表的數(shù)據(jù)拆成多張表來(lái)存放。舉個(gè)例子:我們可以將用戶信息表拆分成多個(gè)用戶信息表,這樣就可以避免單一表數(shù)據(jù)量過(guò)大對(duì)性能造成影響。

水品拆分可以支持非常大的數(shù)據(jù)量。需要注意的一點(diǎn)是:分表僅僅是解決了單一表數(shù)據(jù)過(guò)大的問(wèn)題,但由于表的數(shù)據(jù)還是在同一臺(tái)機(jī)器上,其實(shí)對(duì)于提升MySQL并發(fā)能力沒(méi)有什么意義,所以 水品拆分最好分庫(kù) 。
水平拆分能夠 支持非常大的數(shù)據(jù)量存儲(chǔ),應(yīng)用端改造也少,但 分片事務(wù)難以解決 ,跨界點(diǎn)Join性能較差,邏輯復(fù)雜?!禞ava工程師修煉之道》的作者推薦 盡量不要對(duì)數(shù)據(jù)進(jìn)行分片,因?yàn)椴鸱謺?huì)帶來(lái)邏輯、部署、運(yùn)維的各種復(fù)雜度 ,一般的數(shù)據(jù)表在優(yōu)化得當(dāng)?shù)那闆r下支撐千萬(wàn)以下的數(shù)據(jù)量是沒(méi)有太大問(wèn)題的。如果實(shí)在要分片,盡量選擇客戶端分片架構(gòu),這樣可以減少一次和中間件的網(wǎng)絡(luò)I/O。
下面補(bǔ)充一下數(shù)據(jù)庫(kù)分片的兩種常見(jiàn)方案:

客戶端代理: 分片邏輯在應(yīng)用端,封裝在jar包中,通過(guò)修改或者封裝JDBC層來(lái)實(shí)現(xiàn)。 當(dāng)當(dāng)網(wǎng)的 Sharding-JDBC 、阿里的TDDL是兩種比較常用的實(shí)現(xiàn)。
中間件代理: 在應(yīng)用和數(shù)據(jù)中間加了一個(gè)代理層。分片邏輯統(tǒng)一維護(hù)在中間件服務(wù)中。 我們現(xiàn)在談的 Mycat 、360的Atlas、網(wǎng)易的DDB等等都是這種架構(gòu)的實(shí)現(xiàn)。

五 Redis

關(guān)于 redis 必知必會(huì)的11個(gè)問(wèn)題!后兩個(gè)問(wèn)題,暫未更新!如有需要,可以關(guān)注我的 Github 或者微信公眾號(hào):“Java面試通關(guān)手冊(cè)”獲取后續(xù)更新內(nèi)容。

redis 簡(jiǎn)介
為什么要用 redis /為什么要用緩存
為什么要用 redis 而不用 map/guava 做緩存?
redis 和 memcached 的區(qū)別
redis 常見(jiàn)數(shù)據(jù)結(jié)構(gòu)以及使用場(chǎng)景分析
redis 設(shè)置過(guò)期時(shí)間
redis 內(nèi)存淘汰機(jī)制
redis 持久化機(jī)制(怎么保證 redis 掛掉之后再重啟數(shù)據(jù)可以進(jìn)行恢復(fù))
緩存雪崩和緩存穿透問(wèn)題解決方案
如何解決 Redis 的并發(fā)競(jìng)爭(zhēng) Key 問(wèn)題
如何保證緩存與數(shù)據(jù)庫(kù)雙寫(xiě)時(shí)的數(shù)據(jù)一致性?

5.1 redis 簡(jiǎn)介
Redis 是一個(gè)開(kāi)源(BSD許可)的,內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)系統(tǒng),它可以用作數(shù)據(jù)庫(kù)、緩存和消息中間件。 它支持多種類型的數(shù)據(jù)結(jié)構(gòu),如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 與范圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢。 Redis 內(nèi)置了 復(fù)制(replication),LUA腳本(Lua scripting), LRU驅(qū)動(dòng)事件(LRU eviction),事務(wù)(transactions) 和不同級(jí)別的 磁盤(pán)持久化(persistence), 并通過(guò) Redis哨兵(Sentinel)和自動(dòng) 分區(qū)(Cluster)提供高可用性(high availability)。
5.2 為什么要用 redis /為什么要用緩存
主要從“高性能”和“高并發(fā)”這兩點(diǎn)來(lái)看待這個(gè)問(wèn)題。
高性能:
假如用戶第一次訪問(wèn)數(shù)據(jù)庫(kù)中的某些數(shù)據(jù)。這個(gè)過(guò)程會(huì)比較慢,因?yàn)槭菑挠脖P(pán)上讀取的。將該用戶訪問(wèn)的數(shù)據(jù)存在數(shù)緩存中,這樣下一次再訪問(wèn)這些數(shù)據(jù)的時(shí)候就可以直接從緩存中獲取了。操作緩存就是直接操作內(nèi)存,所以速度相當(dāng)快。如果數(shù)據(jù)庫(kù)中的對(duì)應(yīng)數(shù)據(jù)改變的之后,同步改變緩存中相應(yīng)的數(shù)據(jù)即可!

高并發(fā):
直接操作緩存能夠承受的請(qǐng)求是遠(yuǎn)遠(yuǎn)大于直接訪問(wèn)數(shù)據(jù)庫(kù)的,所以我們可以考慮把數(shù)據(jù)庫(kù)中的部分?jǐn)?shù)據(jù)轉(zhuǎn)移到緩存中去,這樣用戶的一部分請(qǐng)求會(huì)直接到緩存這里而不用經(jīng)過(guò)數(shù)據(jù)庫(kù)。

5.3 為什么要用 redis 而不用 map/guava 做緩存?

緩存分為本地緩存和分布式緩存。以java為例,使用自帶的map或者guava實(shí)現(xiàn)的是本地緩存,最主要的特點(diǎn)是輕量以及快速,生命周期隨著 jvm 的銷毀而結(jié)束,并且在多實(shí)例的情況下,每個(gè)實(shí)例都需要各自保存一份緩存,緩存不具有一致性。
使用 redis 或 memcached 之類的稱為分布式緩存,在多實(shí)例的情況下,各實(shí)例共用一份緩存數(shù)據(jù),緩存具有一致性。缺點(diǎn)是需要保持 redis 或 memcached服務(wù)的高可用,整個(gè)程序架構(gòu)上較為復(fù)雜。
5.4 redis 和 memcached 的區(qū)別
對(duì)于 redis 和 memcached 我總結(jié)了下面四點(diǎn)?,F(xiàn)在公司一般都是用 redis 來(lái)實(shí)現(xiàn)緩存,而且 redis 自身也越來(lái)越強(qiáng)大了!

redis支持更豐富的數(shù)據(jù)類型(支持更復(fù)雜的應(yīng)用場(chǎng)景):Redis不僅僅支持簡(jiǎn)單的k/v類型的數(shù)據(jù),同時(shí)還提供list,set,zset,hash等數(shù)據(jù)結(jié)構(gòu)的存儲(chǔ)。memcache支持簡(jiǎn)單的數(shù)據(jù)類型,String。
Redis支持?jǐn)?shù)據(jù)的持久化,可以將內(nèi)存中的數(shù)據(jù)保持在磁盤(pán)中,重啟的時(shí)候可以再次加載進(jìn)行使用,而Memecache把數(shù)據(jù)全部存在內(nèi)存之中。
集群模式:memcached沒(méi)有原生的集群模式,需要依靠客戶端來(lái)實(shí)現(xiàn)往集群中分片寫(xiě)入數(shù)據(jù);但是redis目前是原生支持cluster模式的,redis官方就是支持redis cluster集群模式的,比memcached來(lái)說(shuō)要更好。
Memcached是多線程,非阻塞IO復(fù)用的網(wǎng)絡(luò)模型;Redis使用單線程的多路 IO 復(fù)用模型。

來(lái)自網(wǎng)絡(luò)上的一張圖,這里分享給大家!

5.5 redis 常見(jiàn)數(shù)據(jù)結(jié)構(gòu)以及使用場(chǎng)景分析

String

常用命令: set,get,decr,incr,mget 等。

String數(shù)據(jù)結(jié)構(gòu)是簡(jiǎn)單的key-value類型,value其實(shí)不僅可以是String,也可以是數(shù)字。
常規(guī)key-value緩存應(yīng)用;
常規(guī)計(jì)數(shù):微博數(shù),粉絲數(shù)等。
2.Hash

常用命令: hget,hset,hgetall 等。

Hash 是一個(gè) string 類型的 field 和 value 的映射表,hash 特別適合用于存儲(chǔ)對(duì)象,后續(xù)操作的時(shí)候,你可以直接僅僅修改這個(gè)對(duì)象中的某個(gè)字段的值。 比如我們可以Hash數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)用戶信息,商品信息等等。比如下面我就用 hash 類型存放了我本人的一些信息:
key=JavaUser293847
value={
“id”: 1,
“name”: “SnailClimb”,
“age”: 22,
“l(fā)ocation”: “Wuhan, Hubei”
}

復(fù)制代碼3.List

常用命令: lpush,rpush,lpop,rpop,lrange等

list就是鏈表,Redis list的應(yīng)用場(chǎng)景非常多,也是Redis最重要的數(shù)據(jù)結(jié)構(gòu)之一,比如微博的關(guān)注列表,粉絲列表,消息列表等功能都可以用Redis的 list 結(jié)構(gòu)來(lái)實(shí)現(xiàn)。
Redis list 的實(shí)現(xiàn)為一個(gè)雙向鏈表,即可以支持反向查找和遍歷,更方便操作,不過(guò)帶來(lái)了部分額外的內(nèi)存開(kāi)銷。
另外可以通過(guò) lrange 命令,就是從某個(gè)元素開(kāi)始讀取多少個(gè)元素,可以基于 list 實(shí)現(xiàn)分頁(yè)查詢,這個(gè)很棒的一個(gè)功能,基于 redis 實(shí)現(xiàn)簡(jiǎn)單的高性能分頁(yè),可以做類似微博那種下拉不斷分頁(yè)的東西(一頁(yè)一頁(yè)的往下走),性能高。
4.Set

常用命令:
sadd,spop,smembers,sunion 等

set對(duì)外提供的功能與list類似是一個(gè)列表的功能,特殊之處在于set是可以自動(dòng)排重的。
當(dāng)你需要存儲(chǔ)一個(gè)列表數(shù)據(jù),又不希望出現(xiàn)重復(fù)數(shù)據(jù)時(shí),set是一個(gè)很好的選擇,并且set提供了判斷某個(gè)成員是否在一個(gè)set集合內(nèi)的重要接口,這個(gè)也是list所不能提供的??梢曰?set 輕易實(shí)現(xiàn)交集、并集、差集的操作。
比如:在微博應(yīng)用中,可以將一個(gè)用戶所有的關(guān)注人存在一個(gè)集合中,將其所有粉絲存在一個(gè)集合。Redis可以非常方便的實(shí)現(xiàn)如共同關(guān)注、共同粉絲、共同喜好等功能。這個(gè)過(guò)程也就是求交集的過(guò)程,具體命令如下:
sinterstore key1 key2 key3 將交集存在key1內(nèi)
復(fù)制代碼5.Sorted Set

常用命令: zadd,zrange,zrem,zcard等

和set相比,sorted set增加了一個(gè)權(quán)重參數(shù)score,使得集合中的元素能夠按score進(jìn)行有序排列。
舉例: 在直播系統(tǒng)中,實(shí)時(shí)排行信息包含直播間在線用戶列表,各種禮物排行榜,彈幕消息(可以理解為按消息維度的消息排行榜)等信息,適合使用 Redis 中的 SortedSet 結(jié)構(gòu)進(jìn)行存儲(chǔ)。
5.6 redis 設(shè)置過(guò)期時(shí)間
Redis中有個(gè)設(shè)置時(shí)間過(guò)期的功能,即對(duì)存儲(chǔ)在 redis 數(shù)據(jù)庫(kù)中的值可以設(shè)置一個(gè)過(guò)期時(shí)間。作為一個(gè)緩存數(shù)據(jù)庫(kù),這是非常實(shí)用的。如我們一般項(xiàng)目中的token或者一些登錄信息,尤其是短信驗(yàn)證碼都是有時(shí)間限制的,按照傳統(tǒng)的數(shù)據(jù)庫(kù)處理方式,一般都是自己判斷過(guò)期,這樣無(wú)疑會(huì)嚴(yán)重影響項(xiàng)目性能。
我們set key的時(shí)候,都可以給一個(gè)expire time,就是過(guò)期時(shí)間,通過(guò)過(guò)期時(shí)間我們可以指定這個(gè) key 可以存貨的時(shí)間。
如果假設(shè)你設(shè)置一個(gè)一批 key 只能存活1個(gè)小時(shí),那么接下來(lái)1小時(shí)后,redis是怎么對(duì)這批key進(jìn)行刪除的?
定期刪除+惰性刪除。
通過(guò)名字大概就能猜出這兩個(gè)刪除方式的意思了。

定期刪除:redis默認(rèn)是每隔 100ms 就隨機(jī)抽取一些設(shè)置了過(guò)期時(shí)間的key,檢查其是否過(guò)期,如果過(guò)期就刪除。注意這里是隨機(jī)抽取的。為什么要隨機(jī)呢?你想一想假如 redis 存了幾十萬(wàn)個(gè) key ,每隔100ms就遍歷所有的設(shè)置過(guò)期時(shí)間的 key 的話,就會(huì)給 CPU 帶來(lái)很大的負(fù)載!
惰性刪除 :定期刪除可能會(huì)導(dǎo)致很多過(guò)期 key 到了時(shí)間并沒(méi)有被刪除掉。所以就有了惰性刪除。假如你的過(guò)期 key,靠定期刪除沒(méi)有被刪除掉,還停留在內(nèi)存里,除非你的系統(tǒng)去查一下那個(gè) key,才會(huì)被redis給刪除掉。這就是所謂的惰性刪除,也是夠懶的哈!

但是僅僅通過(guò)設(shè)置過(guò)期時(shí)間還是有問(wèn)題的。我們想一下:如果定期刪除漏掉了很多過(guò)期 key,然后你也沒(méi)及時(shí)去查,也就沒(méi)走惰性刪除,此時(shí)會(huì)怎么樣?如果大量過(guò)期key堆積在內(nèi)存里,導(dǎo)致redis內(nèi)存塊耗盡了。怎么解決這個(gè)問(wèn)題呢?
redis 內(nèi)存淘汰機(jī)制。
5.7 redis 內(nèi)存淘汰機(jī)制(MySQL里有2000w數(shù)據(jù),Redis中只存20w的數(shù)據(jù),如何保證Redis中的數(shù)據(jù)都是熱點(diǎn)數(shù)據(jù)?)
redis 配置文件 redis.conf 中有相關(guān)注釋,我這里就不貼了,大家可以自行查閱或者通過(guò)這個(gè)網(wǎng)址查看: download.redis.io/redis-stabl…
redis 提供 6種數(shù)據(jù)淘汰策略:

volatile-lru:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰
volatile-ttl:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選將要過(guò)期的數(shù)據(jù)淘汰
volatile-random:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中任意選擇數(shù)據(jù)淘汰
allkeys-lru:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在鍵空間中,移除最近最少使用的key(這個(gè)是最常用的).
allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰
no-enviction:禁止驅(qū)逐數(shù)據(jù),也就是說(shuō)當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),新寫(xiě)入操作會(huì)報(bào)錯(cuò)。這個(gè)應(yīng)該沒(méi)人使用吧!

備注: 關(guān)于 redis 設(shè)置過(guò)期時(shí)間以及內(nèi)存淘汰機(jī)制,我這里只是簡(jiǎn)單的總結(jié)一下,后面會(huì)專門寫(xiě)一篇文章來(lái)總結(jié)!
5.8 redis 持久化機(jī)制(怎么保證 redis 掛掉之后再重啟數(shù)據(jù)可以進(jìn)行恢復(fù))
很多時(shí)候我們需要持久化數(shù)據(jù)也就是將內(nèi)存中的數(shù)據(jù)寫(xiě)入到硬盤(pán)里面,大部分原因是為了之后重用數(shù)據(jù)(比如重啟機(jī)器、機(jī)器故障之后回復(fù)數(shù)據(jù)),或者是為了防止系統(tǒng)故障而將數(shù)據(jù)備份到一個(gè)遠(yuǎn)程位置。
Redis不同于Memcached的很重一點(diǎn)就是,Redis支持持久化,而且支持兩種不同的持久化操作。Redis的一種持久化方式叫快照(snapshotting,RDB),另一種方式是只追加文件(append-only file,AOF).這兩種方法各有千秋,下面我會(huì)詳細(xì)這兩種持久化方法是什么,怎么用,如何選擇適合自己的持久化方法。
快照(snapshotting)持久化(RDB)
Redis可以通過(guò)創(chuàng)建快照來(lái)獲得存儲(chǔ)在內(nèi)存里面的數(shù)據(jù)在某個(gè)時(shí)間點(diǎn)上的副本。Redis創(chuàng)建快照之后,可以對(duì)快照進(jìn)行備份,可以將快照復(fù)制到其他服務(wù)器從而創(chuàng)建具有相同數(shù)據(jù)的服務(wù)器副本(Redis主從結(jié)構(gòu),主要用來(lái)提高Redis性能),還可以將快照留在原地以便重啟服務(wù)器的時(shí)候使用。
快照持久化是Redis默認(rèn)采用的持久化方式,在redis.conf配置文件中默認(rèn)有此下配置:

save 900 1 #在900秒(15分鐘)之后,如果至少有1個(gè)key發(fā)生變化,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。

save 300 10 #在300秒(5分鐘)之后,如果至少有10個(gè)key發(fā)生變化,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。

save 60 10000 #在60秒(1分鐘)之后,如果至少有10000個(gè)key發(fā)生變化,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。
復(fù)制代碼AOF(append-only file)持久化
與快照持久化相比,AOF持久化 的實(shí)時(shí)性更好,因此已成為主流的持久化方案。默認(rèn)情況下Redis沒(méi)有開(kāi)啟AOF(append only file)方式的持久化,可以通過(guò)appendonly參數(shù)開(kāi)啟:
appendonly yes
復(fù)制代碼開(kāi)啟AOF持久化后每執(zhí)行一條會(huì)更改Redis中的數(shù)據(jù)的命令,Redis就會(huì)將該命令寫(xiě)入硬盤(pán)中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通過(guò)dir參數(shù)設(shè)置的,默認(rèn)的文件名是appendonly.aof。
在Redis的配置文件中存在三種不同的 AOF 持久化方式,它們分別是:
appendfsync always #每次有數(shù)據(jù)修改發(fā)生時(shí)都會(huì)寫(xiě)入AOF文件,這樣會(huì)嚴(yán)重降低Redis的速度
appendfsync everysec #每秒鐘同步一次,顯示地將多個(gè)寫(xiě)命令同步到硬盤(pán)
appendfsync no #讓操作系統(tǒng)決定何時(shí)進(jìn)行同步
復(fù)制代碼為了兼顧數(shù)據(jù)和寫(xiě)入性能,用戶可以考慮 appendfsync everysec選項(xiàng) ,讓Redis每秒同步一次AOF文件,Redis性能幾乎沒(méi)受到任何影響。而且這樣即使出現(xiàn)系統(tǒng)崩潰,用戶最多只會(huì)丟失一秒之內(nèi)產(chǎn)生的數(shù)據(jù)。當(dāng)硬盤(pán)忙于執(zhí)行寫(xiě)入操作的時(shí)候,Redis還會(huì)優(yōu)雅的放慢自己的速度以便適應(yīng)硬盤(pán)的最大寫(xiě)入速度。
補(bǔ)充內(nèi)容:AOF 重寫(xiě)
AOF重寫(xiě)可以產(chǎn)生一個(gè)新的AOF文件,這個(gè)新的AOF文件和原有的AOF文件所保存的數(shù)據(jù)庫(kù)狀態(tài)一樣,但體積更小。
AOF重寫(xiě)是一個(gè)有歧義的名字,該功能是通過(guò)讀取數(shù)據(jù)庫(kù)中的鍵值對(duì)來(lái)實(shí)現(xiàn)的,程序無(wú)須對(duì)現(xiàn)有AOF文件進(jìn)行任伺讀入、分析或者寫(xiě)人操作。
在執(zhí)行 BGREWRITEAOF 命令時(shí),Redis 服務(wù)器會(huì)維護(hù)一個(gè) AOF 重寫(xiě)緩沖區(qū),該緩沖區(qū)會(huì)在子進(jìn)程創(chuàng)建新AOF文件期間,記錄服務(wù)器執(zhí)行的所有寫(xiě)命令。當(dāng)子進(jìn)程完成創(chuàng)建新AOF文件的工作之后,服務(wù)器會(huì)將重寫(xiě)緩沖區(qū)中的所有內(nèi)容追加到新AOF文件的末尾,使得新舊兩個(gè)AOF文件所保存的數(shù)據(jù)庫(kù)狀態(tài)一致。最后,服務(wù)器用新的AOF文件替換舊的AOF文件,以此來(lái)完成AOF文件重寫(xiě)操作

5.9 緩存雪崩和緩存穿透問(wèn)題解決方案
緩存雪崩
簡(jiǎn)介:緩存同一時(shí)間大面積的失效,所以,后面的請(qǐng)求都會(huì)落到數(shù)據(jù)庫(kù)上,造成數(shù)據(jù)庫(kù)短時(shí)間內(nèi)承受大量請(qǐng)求而崩掉。
解決辦法(中華石杉老師在他的視頻中提到過(guò)):

事前:盡量保證整個(gè) redis 集群的高可用性,發(fā)現(xiàn)機(jī)器宕機(jī)盡快補(bǔ)上。選擇合適的內(nèi)存淘汰策略。
事中:本地ehcache緩存 + hystrix限流&降級(jí),避免MySQL崩掉
事后:利用 redis 持久化機(jī)制保存的數(shù)據(jù)盡快恢復(fù)緩存

緩存穿透
簡(jiǎn)介:一般是黑客故意去請(qǐng)求緩存中不存在的數(shù)據(jù),導(dǎo)致所有的請(qǐng)求都落到數(shù)據(jù)庫(kù)上,造成數(shù)據(jù)庫(kù)短時(shí)間內(nèi)承受大量請(qǐng)求而崩掉。
解決辦法: 有很多種方法可以有效地解決緩存穿透問(wèn)題,最常見(jiàn)的則是采用布隆過(guò)濾器,將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的bitmap中,一個(gè)一定不存在的數(shù)據(jù)會(huì)被 這個(gè)bitmap攔截掉,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢壓力。另外也有一個(gè)更為簡(jiǎn)單粗暴的方法(我們采用的就是這種),如果一個(gè)查詢返回的數(shù)據(jù)為空(不管是數(shù) 據(jù)不存在,還是系統(tǒng)故障),我們?nèi)匀话堰@個(gè)空結(jié)果進(jìn)行緩存,但它的過(guò)期時(shí)間會(huì)很短,最長(zhǎng)不超過(guò)五分鐘。

六 Java
6.1 Java 基礎(chǔ)知識(shí)

重載和重寫(xiě)的區(qū)別

重載: 發(fā)生在同一個(gè)類中,方法名必須相同,參數(shù)類型不同、個(gè)數(shù)不同、順序不同,方法返回值和訪問(wèn)修飾符可以不同,發(fā)生在編譯時(shí)。 ??
重寫(xiě): 發(fā)生在父子類中,方法名、參數(shù)列表必須相同,返回值范圍小于等于父類,拋出的異常范圍小于等于父類,訪問(wèn)修飾符范圍大于等于父類;如果父類方法訪問(wèn)修飾符為 private 則子類就不能重寫(xiě)該方法。

String 和 StringBuffer、StringBuilder 的區(qū)別是什么?String 為什么是不可變的?

可變性
?
簡(jiǎn)單的來(lái)說(shuō):String 類中使用 final 關(guān)鍵字字符數(shù)組保存字符串,private?final?char?value[],所以 String 對(duì)象是不可變的。而StringBuilder 與 StringBuffer 都繼承自 AbstractStringBuilder 類,在 AbstractStringBuilder 中也是使用字符數(shù)組保存字符串char[]value 但是沒(méi)有用 final 關(guān)鍵字修飾,所以這兩種對(duì)象都是可變的。
StringBuilder 與 StringBuffer 的構(gòu)造方法都是調(diào)用父類構(gòu)造方法也就是 AbstractStringBuilder 實(shí)現(xiàn)的,大家可以自行查閱源碼。
AbstractStringBuilder.java
abstract class AbstractStringBuilder implements Appendable, CharSequence {

char[] value;
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
    value = new char[capacity];
}

復(fù)制代碼線程安全性
String 中的對(duì)象是不可變的,也就可以理解為常量,線程安全。AbstractStringBuilder 是 StringBuilder 與 StringBuffer 的公共父類,定義了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 對(duì)方法加了同步鎖或者對(duì)調(diào)用的方法加了同步鎖,所以是線程安全的。StringBuilder 并沒(méi)有對(duì)方法進(jìn)行加同步鎖,所以是非線程安全的。
??
性能
每次對(duì) String 類型進(jìn)行改變的時(shí)候,都會(huì)生成一個(gè)新的 String 對(duì)象,然后將指針指向新的 String 對(duì)象。StringBuffer 每次都會(huì)對(duì) StringBuffer 對(duì)象本身進(jìn)行操作,而不是生成新的對(duì)象并改變對(duì)象引用。相同情況下使用 StirngBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的風(fēng)險(xiǎn)。
對(duì)于三者使用的總結(jié):

操作少量的數(shù)據(jù) = String
單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) = StringBuilder
多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) = StringBuffer

自動(dòng)裝箱與拆箱

裝箱:將基本類型用它們對(duì)應(yīng)的引用類型包裝起來(lái);
拆箱:將包裝類型轉(zhuǎn)換為基本數(shù)據(jù)類型;

== 與 equals

== : 它的作用是判斷兩個(gè)對(duì)象的地址是不是相等。即,判斷兩個(gè)對(duì)象是不是同一個(gè)對(duì)象。(基本數(shù)據(jù)類型==比較的是值,引用數(shù)據(jù)類型==比較的是內(nèi)存地址)
equals() : 它的作用也是判斷兩個(gè)對(duì)象是否相等。但它一般有兩種使用情況:

情況1:類沒(méi)有覆蓋 equals() 方法。則通過(guò) equals() 比較該類的兩個(gè)對(duì)象時(shí),等價(jià)于通過(guò)“==”比較這兩個(gè)對(duì)象。
情況2:類覆蓋了 equals() 方法。一般,我們都覆蓋 equals() 方法來(lái)兩個(gè)對(duì)象的內(nèi)容相等;若它們的內(nèi)容相等,則返回 true (即,認(rèn)為這兩個(gè)對(duì)象相等)。

舉個(gè)例子:
public class test1 {

public static void main(String[] args) {
    String a = new String("ab"); // a 為一個(gè)引用
    String b = new String("ab"); // b為另一個(gè)引用,對(duì)象的內(nèi)容一樣
    String aa = "ab"; // 放在常量池中
    String bb = "ab"; // 從常量池中查找
    if (aa == bb) // true
        System.out.println("aa==bb");
    if (a == b) // false,非同一對(duì)象
        System.out.println("a==b");
    if (a.equals(b)) // true
        System.out.println("aEQb");
    if (42 == 42.0) { // true
        System.out.println("true");
    }
}

}
復(fù)制代碼說(shuō)明:

String 中的 equals 方法是被重寫(xiě)過(guò)的,因?yàn)?object 的 equals 方法是比較的對(duì)象的內(nèi)存地址,而 String 的 equals 方法比較的是對(duì)象的值。
當(dāng)創(chuàng)建 String 類型的對(duì)象時(shí),虛擬機(jī)會(huì)在常量池中查找有沒(méi)有已經(jīng)存在的值和要?jiǎng)?chuàng)建的值相同的對(duì)象,如果有就把它賦給當(dāng)前引用。如果沒(méi)有就在常量池中重新創(chuàng)建一個(gè) String 對(duì)象。

關(guān)于 final 關(guān)鍵字的一些總結(jié)

final關(guān)鍵字主要用在三個(gè)地方:變量、方法、類。

對(duì)于一個(gè)final變量,如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始化之后便不能更改;如果是引用類型的變量,則在對(duì)其初始化之后便不能再讓其指向另一個(gè)對(duì)象。
當(dāng)用final修飾一個(gè)類時(shí),表明這個(gè)類不能被繼承。final類中的所有成員方法都會(huì)被隱式地指定為final方法。
使用final方法的原因有兩個(gè)。第一個(gè)原因是把方法鎖定,以防任何繼承類修改它的含義;第二個(gè)原因是效率。在早期的Java實(shí)現(xiàn)版本中,會(huì)將final方法轉(zhuǎn)為內(nèi)嵌調(diào)用。但是如果方法過(guò)于龐大,可能看不到內(nèi)嵌調(diào)用帶來(lái)的任何性能提升(現(xiàn)在的Java版本已經(jīng)不需要使用final方法進(jìn)行這些優(yōu)化了)。類中所有的private方法都隱式地指定為fianl。

6.2 Java 集合框架

Arraylist 與 LinkedList 異同

是否保證線程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保證線程安全;

底層數(shù)據(jù)結(jié)構(gòu): Arraylist 底層使用的是Object數(shù)組;LinkedList 底層使用的是雙向循環(huán)鏈表數(shù)據(jù)結(jié)構(gòu);

插入和刪除是否受元素位置的影響: ① ArrayList 采用數(shù)組存儲(chǔ),所以插入和刪除元素的時(shí)間復(fù)雜度受元素位置的影響。 比如:執(zhí)行add(E e)方法的時(shí)候, ArrayList 會(huì)默認(rèn)在將指定的元素追加到此列表的末尾,這種情況時(shí)間復(fù)雜度就是O(1)。但是如果要在指定位置 i 插入和刪除元素的話(add(int index, E element))時(shí)間復(fù)雜度就為 O(n-i)。因?yàn)樵谶M(jìn)行上述操作的時(shí)候集合中第 i 和第 i 個(gè)元素之后的(n-i)個(gè)元素都要執(zhí)行向后位/向前移一位的操作。 ② LinkedList 采用鏈表存儲(chǔ),所以插入,刪除元素時(shí)間復(fù)雜度不受元素位置的影響,都是近似 O(1)而數(shù)組為近似 O(n)。

是否支持快速隨機(jī)訪問(wèn): LinkedList 不支持高效的隨機(jī)元素訪問(wèn),而ArrayList 實(shí)現(xiàn)了RandmoAccess 接口,所以有隨機(jī)訪問(wèn)功能??焖匐S機(jī)訪問(wèn)就是通過(guò)元素的序號(hào)快速獲取元素對(duì)象(對(duì)應(yīng)于get(int index)方法)。

內(nèi)存空間占用: ArrayList的空 間浪費(fèi)主要體現(xiàn)在在list列表的結(jié)尾會(huì)預(yù)留一定的容量空間,而LinkedList的空間花費(fèi)則體現(xiàn)在它的每一個(gè)元素都需要消耗比ArrayList更多的空間(因?yàn)橐娣胖苯雍罄^和直接前驅(qū)以及數(shù)據(jù))。

補(bǔ)充:數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)之雙向鏈表
雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個(gè)數(shù)據(jù)結(jié)點(diǎn)中都有兩個(gè)指針,分別指向直接后繼和直接前驅(qū)。所以,從雙向鏈表中的任意一個(gè)結(jié)點(diǎn)開(kāi)始,都可以很方便地訪問(wèn)它的前驅(qū)結(jié)點(diǎn)和后繼結(jié)點(diǎn)。一般我們都構(gòu)造雙向循環(huán)鏈表,如下圖所示,同時(shí)下圖也是LinkedList 底層使用的是雙向循環(huán)鏈表數(shù)據(jù)結(jié)構(gòu)。

ArrayList 與 Vector 區(qū)別

Vector類的所有方法都是同步的??梢杂蓛蓚€(gè)線程安全地訪問(wèn)一個(gè)Vector對(duì)象、但是一個(gè)線程訪問(wèn)Vector的話代碼要在同步操作上耗費(fèi)大量的時(shí)間。
Arraylist不是同步的,所以在不需要保證線程安全時(shí)時(shí)建議使用Arraylist。

HashMap的底層實(shí)現(xiàn)

①JDK1.8之前
JDK1.8 之前 HashMap 底層是 數(shù)組和鏈表 結(jié)合在一起使用也就是 鏈表散列。HashMap 通過(guò) key 的 hashCode 經(jīng)過(guò)擾動(dòng)函數(shù)處理過(guò)后得到 hash 值,然后通過(guò) (n - 1) & hash 判斷當(dāng)前元素存放的位置(這里的 n 指的時(shí)數(shù)組的長(zhǎng)度),如果當(dāng)前位置存在元素的話,就判斷該元素與要存入的元素的 hash 值以及 key 是否相同,如果相同的話,直接覆蓋,不相同就通過(guò)拉鏈法解決沖突。
所謂擾動(dòng)函數(shù)指的就是 HashMap 的 hash 方法。使用 hash 方法也就是擾動(dòng)函數(shù)是為了防止一些實(shí)現(xiàn)比較差的 hashCode() 方法 換句話說(shuō)使用擾動(dòng)函數(shù)之后可以減少碰撞。
JDK 1.8 HashMap 的 hash 方法源碼:
JDK 1.8 的 hash方法 相比于 JDK 1.7 hash 方法更加簡(jiǎn)化,但是原理不變。

static final int hash(Object key) {
  int h;
  // key.hashCode():返回散列值也就是hashcode
  // ^ :按位異或
  // >>>:無(wú)符號(hào)右移,忽略符號(hào)位,空位都以0補(bǔ)齊
  return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

}
復(fù)制代碼對(duì)比一下 JDK1.7的 HashMap 的 hash 方法源碼.
static int hash(int h) {

// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).

h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);

}
復(fù)制代碼相比于 JDK1.8 的 hash 方法 ,JDK 1.7 的 hash 方法的性能會(huì)稍差一點(diǎn)點(diǎn),因?yàn)楫吘箶_動(dòng)了 4 次。
所謂 “拉鏈法” 就是:將鏈表和數(shù)組相結(jié)合。也就是說(shuō)創(chuàng)建一個(gè)鏈表數(shù)組,數(shù)組中每一格就是一個(gè)鏈表。若遇到哈希沖突,則將沖突的值加到鏈表中即可。

②JDK1.8之后
相比于之前的版本, JDK1.8之后在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長(zhǎng)度大于閾值(默認(rèn)為8)時(shí),將鏈表轉(zhuǎn)化為紅黑樹(shù),以減少搜索時(shí)間。

TreeMap、TreeSet以及JDK1.8之后的HashMap底層都用到了紅黑樹(shù)。紅黑樹(shù)就是為了解決二叉查找樹(shù)的缺陷,因?yàn)槎娌檎覙?shù)在某些情況下會(huì)退化成一個(gè)線性結(jié)構(gòu)。

HashMap 和 Hashtable 的區(qū)別

線程是否安全: HashMap 是非線程安全的,HashTable 是線程安全的;HashTable 內(nèi)部的方法基本都經(jīng)過(guò) synchronized 修飾。(如果你要保證線程安全的話就使用 ConcurrentHashMap 吧?。?br>效率: 因?yàn)榫€程安全的問(wèn)題,HashMap 要比 HashTable 效率高一點(diǎn)。另外,HashTable 基本被淘汰,不要在代碼中使用它;
對(duì)Null key 和Null value的支持: HashMap 中,null 可以作為鍵,這樣的鍵只有一個(gè),可以有一個(gè)或多個(gè)鍵所對(duì)應(yīng)的值為 null。。但是在 HashTable 中 put 進(jìn)的鍵值只要有一個(gè) null,直接拋出 NullPointerException。
初始容量大小和每次擴(kuò)充容量大小的不同 : ①創(chuàng)建時(shí)如果不指定容量初始值,Hashtable 默認(rèn)的初始大小為11,之后每次擴(kuò)充,容量變?yōu)樵瓉?lái)的2n+1。HashMap 默認(rèn)的初始化大小為16。之后每次擴(kuò)充,容量變?yōu)樵瓉?lái)的2倍。②創(chuàng)建時(shí)如果給定了容量初始值,那么 Hashtable 會(huì)直接使用你給定的大小,而 HashMap 會(huì)將其擴(kuò)充為2的冪次方大小。也就是說(shuō) HashMap 總是使用2的冪作為哈希表的大小,后面會(huì)介紹到為什么是2的冪次方。
底層數(shù)據(jù)結(jié)構(gòu): JDK1.8 以后的 HashMap 在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長(zhǎng)度大于閾值(默認(rèn)為8)時(shí),將鏈表轉(zhuǎn)化為紅黑樹(shù),以減少搜索時(shí)間。Hashtable 沒(méi)有這樣的機(jī)制。

HashMap 的長(zhǎng)度為什么是2的冪次方

為了能讓 HashMap 存取高效,盡量較少碰撞,也就是要盡量把數(shù)據(jù)分配均勻。我們上面也講到了過(guò)了,Hash 值的范圍值-2147483648到2147483648,前后加起來(lái)大概40億的映射空間,只要哈希函數(shù)映射得比較均勻松散,一般應(yīng)用是很難出現(xiàn)碰撞的。但問(wèn)題是一個(gè)40億長(zhǎng)度的數(shù)組,內(nèi)存是放不下的。所以這個(gè)散列值是不能直接拿來(lái)用的。用之前還要先做對(duì)數(shù)組的長(zhǎng)度取模運(yùn)算,得到的余數(shù)才能用來(lái)要存放的位置也就是對(duì)應(yīng)的數(shù)組下標(biāo)。
這個(gè)算法應(yīng)該如何設(shè)計(jì)呢?
我們首先可能會(huì)想到采用%取余的操作來(lái)實(shí)現(xiàn)。但是,重點(diǎn)來(lái)了:“取余(%)操作中如果除數(shù)是2的冪次則等價(jià)于與其除數(shù)減一的與(&)操作(也就是說(shuō) hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。” 并且 采用二進(jìn)制位操作 &,相對(duì)于%能夠提高運(yùn)算效率,這就解釋了 HashMap 的長(zhǎng)度為什么是2的冪次方。

HashMap 多線程操作導(dǎo)致死循環(huán)問(wèn)題

在多線程下,進(jìn)行 put 操作會(huì)導(dǎo)致 HashMap 死循環(huán),原因在于 HashMap 的擴(kuò)容 resize()方法。由于擴(kuò)容是新建一個(gè)數(shù)組,復(fù)制原數(shù)據(jù)到數(shù)組。由于數(shù)組下標(biāo)掛有鏈表,所以需要復(fù)制鏈表,但是多線程操作有可能導(dǎo)致環(huán)形鏈表。復(fù)制鏈表過(guò)程如下:
以下模擬2個(gè)線程同時(shí)擴(kuò)容。假設(shè),當(dāng)前 HashMap 的空間為2(臨界值為1),hashcode 分別為 0 和 1,在散列地址 0 處有元素 A 和 B,這時(shí)候要添加元素 C,C 經(jīng)過(guò) hash 運(yùn)算,得到散列地址為 1,這時(shí)候由于超過(guò)了臨界值,空間不夠,需要調(diào)用 resize 方法進(jìn)行擴(kuò)容,那么在多線程條件下,會(huì)出現(xiàn)條件競(jìng)爭(zhēng),模擬過(guò)程如下:
線程一:讀取到當(dāng)前的 HashMap 情況,在準(zhǔn)備擴(kuò)容時(shí),線程二介入

線程二:讀取 HashMap,進(jìn)行擴(kuò)容

線程一:繼續(xù)執(zhí)行

這個(gè)過(guò)程為,先將 A 復(fù)制到新的 hash 表中,然后接著復(fù)制 B 到鏈頭(A 的前邊:B.next=A),本來(lái) B.next=null,到此也就結(jié)束了(跟線程二一樣的過(guò)程),但是,由于線程二擴(kuò)容的原因,將 B.next=A,所以,這里繼續(xù)復(fù)制A,讓 A.next=B,由此,環(huán)形鏈表出現(xiàn):B.next=A; A.next=B

HashSet 和 HashMap 區(qū)別

如果你看過(guò) HashSet 源碼的話就應(yīng)該知道:HashSet 底層就是基于 HashMap 實(shí)現(xiàn)的。(HashSet 的源碼非常非常少,因?yàn)槌?clone() 方法、writeObject()方法、readObject()方法是 HashSet 自己不得不實(shí)現(xiàn)之外,其他方法都是直接調(diào)用 HashMap 中的方法。)

ConcurrentHashMap 和 Hashtable 的區(qū)別

ConcurrentHashMap 和 Hashtable 的區(qū)別主要體現(xiàn)在實(shí)現(xiàn)線程安全的方式上不同。

底層數(shù)據(jù)結(jié)構(gòu): JDK1.7的 ConcurrentHashMap 底層采用 分段的數(shù)組+鏈表 實(shí)現(xiàn),JDK1.8 采用的數(shù)據(jù)結(jié)構(gòu)跟HashMap1.8的結(jié)構(gòu)一樣,數(shù)組+鏈表/紅黑二叉樹(shù)。Hashtable 和 JDK1.8 之前的 HashMap 的底層數(shù)據(jù)結(jié)構(gòu)類似都是采用 數(shù)組+鏈表 的形式,數(shù)組是 HashMap 的主體,鏈表則是主要為了解決哈希沖突而存在的;
實(shí)現(xiàn)線程安全的方式(重要): ① 在JDK1.7的時(shí)候,ConcurrentHashMap(分段鎖) 對(duì)整個(gè)桶數(shù)組進(jìn)行了分割分段(Segment),每一把鎖只鎖容器其中一部分?jǐn)?shù)據(jù),多線程訪問(wèn)容器里不同數(shù)據(jù)段的數(shù)據(jù),就不會(huì)存在鎖競(jìng)爭(zhēng),提高并發(fā)訪問(wèn)率。(默認(rèn)分配16個(gè)Segment,比Hashtable效率提高16倍。) 到了 JDK1.8 的時(shí)候已經(jīng)摒棄了Segment的概念,而是直接用 Node 數(shù)組+鏈表+紅黑樹(shù)的數(shù)據(jù)結(jié)構(gòu)來(lái)實(shí)現(xiàn),并發(fā)控制使用 synchronized 和 CAS 來(lái)操作。(JDK1.6以后 對(duì) synchronized鎖做了很多優(yōu)化) 整個(gè)看起來(lái)就像是優(yōu)化過(guò)且線程安全的 HashMap,雖然在JDK1.8中還能看到 Segment 的數(shù)據(jù)結(jié)構(gòu),但是已經(jīng)簡(jiǎn)化了屬性,只是為了兼容舊版本;② Hashtable(同一把鎖) :使用 synchronized 來(lái)保證線程安全,效率非常低下。當(dāng)一個(gè)線程訪問(wèn)同步方法時(shí),其他線程也訪問(wèn)同步方法,可能會(huì)進(jìn)入阻塞或輪詢狀態(tài),如使用 put 添加元素,另一個(gè)線程不能使用 put 添加元素,也不能使用 get,競(jìng)爭(zhēng)會(huì)越來(lái)越激烈效率越低。

兩者的對(duì)比圖:
圖片來(lái)源:www.cnblogs.com/chengxiao/p…
HashTable:

JDK1.7的ConcurrentHashMap:

JDK1.8的ConcurrentHashMap(TreeBin: 紅黑二叉樹(shù)節(jié)點(diǎn)
Node: 鏈表節(jié)點(diǎn)):

ConcurrentHashMap線程安全的具體實(shí)現(xiàn)方式/底層具體實(shí)現(xiàn)

①JDK1.7(上面有示意圖)
首先將數(shù)據(jù)分為一段一段的存儲(chǔ),然后給每一段數(shù)據(jù)配一把鎖,當(dāng)一個(gè)線程占用鎖訪問(wèn)其中一個(gè)段數(shù)據(jù)時(shí),其他段的數(shù)據(jù)也能被其他線程訪問(wèn)。
ConcurrentHashMap 是由 Segment 數(shù)組結(jié)構(gòu)和 HahEntry 數(shù)組結(jié)構(gòu)組成。
Segment 實(shí)現(xiàn)了 ReentrantLock,所以 Segment 是一種可重入鎖,扮演鎖的角色。HashEntry 用于存儲(chǔ)鍵值對(duì)數(shù)據(jù)。
static class Segment extends ReentrantLock implements Serializable {
}
復(fù)制代碼一個(gè) ConcurrentHashMap 里包含一個(gè) Segment 數(shù)組。Segment 的結(jié)構(gòu)和HashMap類似,是一種數(shù)組和鏈表結(jié)構(gòu),一個(gè) Segment 包含一個(gè) HashEntry 數(shù)組,每個(gè) HashEntry 是一個(gè)鏈表結(jié)構(gòu)的元素,每個(gè) Segment 守護(hù)著一個(gè)HashEntry數(shù)組里的元素,當(dāng)對(duì) HashEntry 數(shù)組的數(shù)據(jù)進(jìn)行修改時(shí),必須首先獲得對(duì)應(yīng)的 Segment的鎖。
②JDK1.8 (上面有示意圖)
ConcurrentHashMap取消了Segment分段鎖,采用CAS和synchronized來(lái)保證并發(fā)安全。數(shù)據(jù)結(jié)構(gòu)跟HashMap1.8的結(jié)構(gòu)類似,數(shù)組+鏈表/紅黑二叉樹(shù)。
synchronized只鎖定當(dāng)前鏈表或紅黑二叉樹(shù)的首節(jié)點(diǎn),這樣只要hash不沖突,就不會(huì)產(chǎn)生并發(fā),效率又提升N倍。

集合框架底層數(shù)據(jù)結(jié)構(gòu)總結(jié)

Collection
1.List

Arraylist: Object數(shù)組

Vector: Object數(shù)組

LinkedList: 雙向循環(huán)鏈表
2.Set

HashSet(無(wú)序,唯一): 基于 HashMap 實(shí)現(xiàn)的,底層采用 HashMap 來(lái)保存元素

LinkedHashSet: LinkedHashSet 繼承與 HashSet,并且其內(nèi)部是通過(guò) LinkedHashMap 來(lái)實(shí)現(xiàn)的。有點(diǎn)類似于我們之前說(shuō)的LinkedHashMap 其內(nèi)部是基于 Hashmap 實(shí)現(xiàn)一樣,不過(guò)還是有一點(diǎn)點(diǎn)區(qū)別的。

TreeSet(有序,唯一): 紅黑樹(shù)(自平衡的排序二叉樹(shù)。)

Map

HashMap: JDK1.8之前HashMap由數(shù)組+鏈表組成的,數(shù)組是HashMap的主體,鏈表則是主要為了解決哈希沖突而存在的(“拉鏈法”解決沖突).JDK1.8以后在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長(zhǎng)度大于閾值(默認(rèn)為8)時(shí),將鏈表轉(zhuǎn)化為紅黑樹(shù),以減少搜索時(shí)間
LinkedHashMap: LinkedHashMap 繼承自 HashMap,所以它的底層仍然是基于拉鏈?zhǔn)缴⒘薪Y(jié)構(gòu)即由數(shù)組和鏈表或紅黑樹(shù)組成。另外,LinkedHashMap 在上面結(jié)構(gòu)的基礎(chǔ)上,增加了一條雙向鏈表,使得上面的結(jié)構(gòu)可以保持鍵值對(duì)的插入順序。同時(shí)通過(guò)對(duì)鏈表進(jìn)行相應(yīng)的操作,實(shí)現(xiàn)了訪問(wèn)順序相關(guān)邏輯。詳細(xì)可以查看:《LinkedHashMap 源碼詳細(xì)分析(JDK1.8)》
HashTable: 數(shù)組+鏈表組成的,數(shù)組是 HashMap 的主體,鏈表則是主要為了解決哈希沖突而存在的
TreeMap: 紅黑樹(shù)(自平衡的排序二叉樹(shù))

6.3 Java多線程
關(guān)于 Java多線程,在面試的時(shí)候,問(wèn)的比較多的就是①悲觀鎖和樂(lè)觀鎖( 具體可以看我的這篇文章:面試必備之樂(lè)觀鎖與悲觀鎖)、②synchronized和lock區(qū)別以及volatile和synchronized的區(qū)別,③可重入鎖與非可重入鎖的區(qū)別、④多線程是解決什么問(wèn)題的、⑤線程池解決什么問(wèn)題、⑥線程池的原理、⑦線程池使用時(shí)的注意事項(xiàng)、⑧AQS原理、⑨ReentranLock源碼,設(shè)計(jì)原理,整體過(guò)程 等等問(wèn)題。
??面試官在多線程這一部分很可能會(huì)問(wèn)你有沒(méi)有在項(xiàng)目中實(shí)際使用多線程的經(jīng)歷。所以,如果你在你的項(xiàng)目中有實(shí)際使用Java多線程的經(jīng)歷 的話,會(huì)為你加分不少哦!
6.4 Java虛擬機(jī)
??關(guān)于Java虛擬機(jī),在面試的時(shí)候一般會(huì)問(wèn)的大多就是①Java內(nèi)存區(qū)域、②虛擬機(jī)垃圾算法、③虛擬機(jī)垃圾收集器、④JVM內(nèi)存管理、⑤JVM調(diào)優(yōu)這些問(wèn)題了。

6.5 設(shè)計(jì)模式
設(shè)計(jì)模式比較常見(jiàn)的就是讓你手寫(xiě)一個(gè)單例模式(注意單例模式的幾種不同的實(shí)現(xiàn)方法)或者讓你說(shuō)一下某個(gè)常見(jiàn)的設(shè)計(jì)模式在你的項(xiàng)目中是如何使用的,另外面試官還有可能問(wèn)你抽象工廠和工廠方法模式的區(qū)別、工廠模式的思想這樣的問(wèn)題。
建議把代理模式、觀察者模式、(抽象)工廠模式好好看一下,這三個(gè)設(shè)計(jì)模式也很重要。
七 數(shù)據(jù)結(jié)構(gòu)
??數(shù)據(jù)結(jié)構(gòu)比較常問(wèn)的就是:二叉樹(shù)、紅黑樹(shù)(很可能讓你手繪一個(gè)紅黑樹(shù)出來(lái)哦?。?、二叉查找樹(shù)(BST)、平衡二叉樹(shù)(Self-balancing binary search tree)、B-樹(shù),B+樹(shù)與B*樹(shù)的優(yōu)缺點(diǎn)比較、 LSM 樹(shù)這些知識(shí)點(diǎn)。
??數(shù)據(jù)結(jié)構(gòu)很重要,而且學(xué)起來(lái)也相對(duì)要難一些。建議學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)一定要循序漸進(jìn)的來(lái),一步一個(gè)腳印的走好。一定要搞懂原理,最好自己能用代碼實(shí)現(xiàn)一遍。
八 算法
??常見(jiàn)的加密算法、排序算法都需要自己提前了解一下,排序算法最好自己能夠獨(dú)立手寫(xiě)出來(lái)。
??我覺(jué)得面試中最刺激、最有壓力或者說(shuō)最有挑戰(zhàn)的一個(gè)環(huán)節(jié)就是手撕算法了。面試中大部分算法題目都是來(lái)自于Leetcode、劍指offer上面,建議大家可以每天擠出一點(diǎn)時(shí)間刷一下算法題。
推薦兩個(gè)刷題必備網(wǎng)站:
LeetCode:

LeetCode(中國(guó))官網(wǎng)
如何高效地使用 LeetCode

??途W(wǎng):

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/77277.html

相關(guān)文章

  • 如何招聘一名優(yōu)秀的前端

    摘要:如何考察一個(gè)人是不是經(jīng)驗(yàn)豐富我們需要在問(wèn)答式的面試中,對(duì)其項(xiàng)目經(jīng)驗(yàn)進(jìn)行挖掘。如何設(shè)置筆試題現(xiàn)在網(wǎng)上有大量的面經(jīng)的存在,對(duì)于我們面試是一個(gè)巨大的挑戰(zhàn)。尊重應(yīng)聘者我們要尊重每一個(gè)來(lái)應(yīng)聘的人,不要輕視別人,或者故意刁難別人。 時(shí)光荏苒,2個(gè)月前,我才剛總結(jié)了如何應(yīng)對(duì)面試官,現(xiàn)在的我開(kāi)始總結(jié)如何面試別人了。笑哭.png 1.我們需要什么樣的人 招聘肯定要有標(biāo)準(zhǔn),這樣我們才能更快的找到我們需要的...

    Mr_houzi 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<