黃莆課堂講java第四節(jié)

**三十一、Redis分布式

image.png

Redis分布式鎖注意事項:

1.設(shè)置過期時間:如果獲取鎖后,系統(tǒng)宕機了,沒有釋放鎖,導(dǎo)致其他線程一致拿不到該鎖,影響業(yè)務(wù)功能,加鎖和設(shè)置過期時間是原子操作

2.過期時間到了業(yè)務(wù)操作還沒完成:增加守護線程,定時對鎖的過期時間進行續(xù)期

3.鎖的釋放:加鎖和釋放必須是同一個人操作,釋放鎖先判斷是不是自己加的

Redission實現(xiàn)分布式鎖,是redis的客戶端,基于Lua腳本執(zhí)行,key的模式過期時間30秒,加鎖之后會基于watchDog(看門狗)機制在后臺啟動一個線程每隔10秒執(zhí)行一次檢查,如果key還在,重置key的生存時間為30秒,redisson也實現(xiàn)可重入鎖的機制,再次加鎖會將key對應(yīng)的hash結(jié)構(gòu)中value+1.

Redission的好處:

  1. 自動續(xù)期功能:watchDog(看門狗)機制在后臺啟動一個線程每隔10秒執(zhí)行一次檢查,如果key還在,重置key的生存時間為30秒

  2. 基本不用寫代碼只能可以拿來用

  3. 過期時間:默認(rèn)30秒

image.png

**三十二、Redis與Memcache區(qū)別:

  1. 數(shù)據(jù)類型:memcached只支持簡單數(shù)據(jù)類型,鍵值對

       Redis:字符串、集合、列表等
    
  2. 內(nèi)存管理:redis可以設(shè)置過期時間

  3. 持久化管理:memcached不提供持久化功能,數(shù)據(jù)僅保存在內(nèi)存中;redis支持持久化,將數(shù)據(jù)保存到磁盤上,防止數(shù)據(jù)丟失。Reids持久化:RDF、AOF、混合方式

使用場景:

緩存內(nèi)容只有字符串、不考慮數(shù)據(jù)持久性、數(shù)據(jù)過期,可以采用memcached

**三十三、HashMap 的實現(xiàn)原理?

HashMap實際是一種“數(shù)組+鏈表”數(shù)據(jù)結(jié)構(gòu),jdk8后數(shù)組+鏈表+紅黑樹

HashMap是基于哈希表的Map接口的非同步實現(xiàn)。實現(xiàn)HashMap對數(shù)據(jù)的操作,允許有一個null鍵,多個null值。

HashMap底層就是一個數(shù)組結(jié)構(gòu),數(shù)組中的每一項又是一個鏈表。數(shù)組+鏈表結(jié)構(gòu),新建一個HashMap的時候,就會初始化一個數(shù)組。Entry就是數(shù)組中的元素,每個Entry其實就是一個key-value的鍵值對,它持有一個指向下一個元素的引用,這就構(gòu)成了鏈表,HashMap底層將key-value當(dāng)成一個整體來處理,這個整體就是一個Entry對象。HashMap底層采用一個Entry【】數(shù)組來保存所有的key-value鍵值對,當(dāng)需要存儲一個Entry對象時,會根據(jù)hash算法來決定在其數(shù)組中的位置,在根據(jù)equals方法決定其在該數(shù)組位置上的鏈表中的存儲位置;當(dāng)需要取出一個Entry對象時,也會根據(jù)hash算法找到其在數(shù)組中的存儲位置, 在根據(jù)equals方法從該位置上的鏈表中取出Entry;

image.png

**三十四、HashMap,HashTable,ConcurrentHash的共同點和區(qū)別

  1. HashMap

底層由鏈表+數(shù)組+紅黑樹實現(xiàn)

可以存儲null鍵和null值

線性不安全

初始容量為16,擴容每次都是2的n次冪

加載因子為0.75,當(dāng)Map中元素總數(shù)超過Entry數(shù)組的0.75,觸發(fā)擴容操作.

并發(fā)情況下,HashMap進行put操作會引起死循環(huán),導(dǎo)致CPU利用率接近100%

HashMap是對Map接口的實現(xiàn)

2.HashTable

HashTable的底層也是由鏈表+數(shù)組+紅黑樹實現(xiàn)。

不能存儲null鍵或null值

它是線性安全的,使用了synchronized關(guān)鍵字。

HashTable實現(xiàn)了Map接口和Dictionary抽象類

Hashtable初始容量為11

3.ConcurrentHashMap

ConcurrentHashMap的底層是數(shù)組+鏈表+紅黑樹

不能存儲null鍵或null值

ConcurrentHashMap是線程安全的

ConcurrentHashMap使用鎖分段技術(shù)確保線性安全,JDK8為何又放棄分段鎖,是因為多個分段鎖浪費內(nèi)存空間,競爭同一個鎖的概率非常小,分段鎖反而會造成效率低。

**三十五、面向?qū)ο?/h3>

面向?qū)ο蟮娜齻€基本特征:封裝、繼承、多態(tài)

1)、封裝(英語:Encapsulation)是指,一種將抽象性函式接口的實現(xiàn)細(xì)節(jié)部份包裝、隱藏起來的方法。封裝可以被認(rèn)為是一個保護屏障,防止該類的代碼和數(shù)據(jù)被外部類定義的代碼隨機訪問。

2)、繼承可以使得子類具有父類的屬性和方法或者重新定義、追加屬性和方法等,繼承可以理解為一個對象從另一個對象獲取屬性的過程。

3)、多態(tài)是同一個行為具有多個不同表現(xiàn)形式或形態(tài)的能力。多態(tài)性是對象多種表現(xiàn)形式的體現(xiàn)。比如我們說"寵物"這個對象,它就有很多不同的表達(dá)或?qū)崿F(xiàn),比如有小貓、小狗、蜥蜴等等。那么我到寵物店說"請給我一只寵物",服務(wù)員給我小貓、小狗或者蜥蜴都可以,我們就說"寵物"這個對象就具備多態(tài)性。

Java 中實現(xiàn)多態(tài)的機制是什么?

方法的重寫 Overriding 和重載 Overloading 是 Java 多態(tài)性的不同表現(xiàn)。重寫 Overriding是父類與子類之間多態(tài)性的一種表現(xiàn),重載 Overloading 是一個類中多態(tài)性的一種表現(xiàn)

**三十六、抽象類(abstract class)和接口(interface)有什么區(qū)別?

1)、抽象類和接口都不能夠?qū)嵗?/p>

2)、接口用interface來修飾

3)、類能實現(xiàn)一個或多個接口,但只能繼承一個抽象類

4)、接口里的方法只能是抽象方法、類方法或者默認(rèn)方法,接口里的方法不能有方法實現(xiàn),但類方法、默認(rèn)方法都必須要實現(xiàn)。

**三十七、為什么重載hashCode方法?

一般的地方不需要重載hashCode,只有當(dāng)類需要放在HashTable、HashMap、HashSet等等hash結(jié)構(gòu)的集合時才會重載hashCode,那么為什么要重載hashCode呢?

如果你重寫了equals,比如說是基于對象的內(nèi)容實現(xiàn)的,而保留hashCode的實現(xiàn)不變,那么很可能某兩個對象明明是“相等”,而hashCode卻不一樣。

這樣,當(dāng)你用其中的一個作為鍵保存到hashMap、hasoTable或hashSet中,再以“相等的”找另一個作為鍵值去查找他們的時候,則根本找不到。

**三十八、== 和 equals 的區(qū)別是什么?

==是操作符,是比較兩個對象的地址或基本類型,equals是比較兩個對象的內(nèi)容,屬于Object里的方法。

**三十九、SQL優(yōu)化

索引查詢、避免全表掃描:查詢數(shù)據(jù)庫的數(shù)據(jù)盡量使用索引來查詢,避免全表掃描。盡量只查詢索引條件的字段

查詢數(shù)據(jù)盡量避免使用or:使用or會導(dǎo)致執(zhí)行sql的時候進行數(shù)據(jù)范圍的索引掃描或者全表掃描,效率降低。

Where條件中:in和not in、對字段進行表達(dá)式操作、對字段進行函數(shù)操作都會導(dǎo)致全表搜索

多張表數(shù)據(jù)查詢,使用inner join代替自查詢,因為子查詢需要在內(nèi)存中創(chuàng)建臨時表來完成這個邏輯上的需要兩個步驟的查詢工作。

使用like進行數(shù)據(jù)表查詢時,能用%就不建議使用雙%:雙%查詢會導(dǎo)致mysql引擎放棄使用索引而進行全表掃描查詢,查詢時盡量把%放后面,或者不適用%。

慢查詢?nèi)罩荆郝樵內(nèi)罩镜氖褂?,在調(diào)試的時候開啟慢查詢,定位的慢查詢語句,再做優(yōu)化策略。關(guān)閉/開啟語句 Slow_query_log=0|1,Long_query_time=N超過該時間臨界點,就為慢查詢

mysql查看sql的執(zhí)行計劃,以此來分析sql執(zhí)行緩慢的問題所在

**四十、鎖

公平鎖:指多個線程按照申請鎖的順序來獲取鎖。

非公平鎖:指多個線程獲取鎖的順序并不是按照申請鎖的順序,有可能后申請的線程比先申請的線程優(yōu)先獲取鎖。有可能,會造成優(yōu)先級反轉(zhuǎn)或者饑餓現(xiàn)象。

可重入鎖:指的是可重復(fù)可遞歸調(diào)用的鎖,在外層使用鎖之后,在內(nèi)層仍然可以使用,并且不發(fā)生死鎖(前提得是同一個對象或者class),例如ReentrantLock和synchronized都是可重入鎖。防止死鎖

不可重入鎖:不可遞歸調(diào)用,遞歸調(diào)用就發(fā)生死鎖

獨享鎖:是指該鎖一次只能被一個線程所持有。 共享鎖:是指該鎖可被多個線程所持有。

悲觀鎖:認(rèn)為對于同一個數(shù)據(jù)的并發(fā)操作,一定是會發(fā)生修改的,哪怕沒有修改,也會認(rèn)為修改。因此對于同一個數(shù)據(jù)的并發(fā)操作,悲觀鎖采取加鎖的形式。悲觀的認(rèn)為,不加鎖的并發(fā)操作一定會出問題

樂觀鎖:則認(rèn)為對于同一個數(shù)據(jù)的并發(fā)操作,是不會發(fā)生修改的。在更新數(shù)據(jù)的時候,會采用嘗試更新,不斷重新的方式更新數(shù)據(jù)。樂觀的認(rèn)為,不加鎖的并發(fā)操作是沒有事情的。

Java鎖機制可歸為Sychornized鎖和Lock鎖兩類。

Synchronized是基于JVM來保證數(shù)據(jù)同步的,底層使用指令碼方式來控制鎖的,映射成字節(jié)碼指令就是增加來兩個指令:monitorenter和monitorexit。當(dāng)線程執(zhí)行遇到monitorenter指令時會嘗試獲取內(nèi)置鎖,如果獲取鎖則鎖計數(shù)器+1,如果沒有獲取鎖則阻塞;當(dāng)遇到monitorexit指令時鎖計數(shù)器-1,如果計數(shù)器為0則釋放鎖。

Lock底層是CAS樂觀鎖,是在硬件層面,通過特殊的CPU指令實現(xiàn)數(shù)據(jù)同步的,依賴AbstractQueuedSynchronizer類,把所有的請求線程構(gòu)成一個CLH隊列。而對該隊列的操作均通過Lock-Free(CAS)操作。與synchronized不同的是,Lock鎖是純Java實現(xiàn)的,與底層的JVM無關(guān)。在java.util.concurrent.locks包中有很多Lock的實現(xiàn)類,常用的有ReentrantLock、ReentrantReadWriteLock,java的Lock接口的子類就是借助AQS來實現(xiàn)了lock和unlock。

ReentrantLock原理

ReentrantLock主要利用CAS+AQS隊列來實現(xiàn),支持公平鎖和非公平鎖。ReentrantLock的基本實現(xiàn)可以概括為:先通過CAS嘗試獲取鎖。如果此時已經(jīng)有線程占據(jù)了鎖,那就加入AQS隊列并且被掛起。當(dāng)鎖被釋放之后,排在CLH隊列隊首的線程會被喚醒,然后CAS再次嘗試獲取鎖。此時,如果:

非公平鎖:如果同時還有另一個線程進來嘗試獲取,那么有可能會讓這個線程搶先獲取

公平鎖:如果同時還有另一個線程進來嘗試獲取,當(dāng)它發(fā)現(xiàn)自己不是在隊首的話,就會排到隊尾,由隊首的線程獲取到鎖

ReentrantLock默認(rèn)構(gòu)造器初始化為NonfairSync對象,由lock()和unlock的源碼可以看到,它們分別調(diào)用了sync對象的lock()和release(1)方法。

Lock與synchronized 的區(qū)別

  1. synchronized會自動釋放鎖、ReentrantLock需要手動釋放鎖(在finally塊中顯示釋放鎖)

  2. Synchronized是非公平鎖,ReentrantLock是可以是公平也可以是非公平的(默認(rèn)非公平)

  3. synchronized是在JVM層面上實現(xiàn)的,Lock是用CAS來實現(xiàn)的

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Java繼承關(guān)系初始化順序 父類的靜態(tài)變量-->父類的靜態(tài)代碼塊-->子類的靜態(tài)變量-->子類的靜態(tài)代碼快-->父...
    第六象限閱讀 2,246評論 0 9
  • 一、java面試題 熟練掌握java是很關(guān)鍵的,大公司不僅僅要求你會使用幾個api,更多的是要你熟悉源碼實現(xiàn)原理,...
    上善若水0819閱讀 3,639評論 0 1
  • JVM 說一下 jvm 的主要組成部分?及其作用? JVM包括類加載子系統(tǒng)、堆、方法區(qū)、棧、本地方法棧、程序計數(shù)器...
    文刀雨木同閱讀 636評論 0 1
  • 目錄:一、Java 基礎(chǔ)二、容器三、多線程四、反射五、對象拷貝六、異常七、設(shè)計模式八、網(wǎng)絡(luò)編程 歡迎評論留言,文章...
    mumuxi_閱讀 834評論 0 13
  • 轉(zhuǎn)眼2021年都快要過完了。 剛剛過去的秋招也是有人歡喜有人愁,不知道在座的各位有沒有拿到心儀的offer,先恭喜...
    Mssyaa閱讀 538評論 0 3

友情鏈接更多精彩內(nèi)容