多線程
死鎖的條件,如何打破,如何避免
四個(gè)條件:
1.互斥 同一資源在同一時(shí)間只能由一個(gè)進(jìn)程占用,其他進(jìn)程只能等待釋放資源。
2.占用且請求 進(jìn)程獨(dú)占資源A同時(shí)申請請求資源B
3.不可剝奪 進(jìn)程在獨(dú)占資源時(shí)不可被其他進(jìn)程強(qiáng)制奪走
4.循環(huán)等待 進(jìn)程間形成循環(huán)等待環(huán)
打破死鎖從以上條件入手:
互斥是資源固有的特性,不可打破。
破壞占用且請求:進(jìn)程在請求資源時(shí)將所有需要獨(dú)占的資源一次性占用?;蛘咦陨聿徽加觅Y源只是請求新的資源。
破壞不可剝奪:進(jìn)程在請求其他進(jìn)程占用的資源時(shí),等待期間釋放自身占用的資源。
破壞循環(huán)等待:將所有資源進(jìn)行順序編號,資源稀缺的給大的編號,進(jìn)程只能先請求小的資源進(jìn)而申請大的。
避免死鎖:
不限制每個(gè)進(jìn)程申請資源的命令,而是動(dòng)態(tài)的在進(jìn)程申請資源命令時(shí)動(dòng)態(tài)的進(jìn)行檢查,通過檢查結(jié)果來是否分配資源。實(shí)現(xiàn)為:銀行家算法。具體算法不詳訴。JMM JVM的共享內(nèi)存模型
如何創(chuàng)建線程池,隊(duì)列都有哪些?拒絕策略都有哪些?任務(wù)過多時(shí)都是如何處理的
創(chuàng)建線程池四種方式
1.newFiexedThreadPool() 創(chuàng)建固定數(shù)量線程的線程池。
2.newCachedThreadPool()創(chuàng)建可緩存的線程池
3.newSingleThreadExecutor()創(chuàng)建單線程的executor
4.newScheduledThreadPool()創(chuàng)建支持定時(shí)及周期性執(zhí)行的線程池
隊(duì)列有三種:
1.有界緩沖隊(duì)列ArrayBlockingQueue 任務(wù)過多時(shí),超過corePoolSize則進(jìn)入定長隊(duì)列,隊(duì)列滿時(shí)啟動(dòng)新線程直到maximumPoolSizes,執(zhí)行拒絕策略
2.無界緩沖隊(duì)列LinkedBlockingQueue,超過corePoolSize則進(jìn)入無界隊(duì)列,maximumPoolSizes無效,這也是為何阿里規(guī)約限制使用Executor的原因。
3.無緩沖等待隊(duì)列SynchronousQueue,不存儲(chǔ)直接交給消費(fèi)者,超過corePoolSize直接新啟動(dòng)線程,達(dá)到maximumPoolSizes則等待。
拒絕策略有四種:
1.丟失拋異常AbortPolicy
2.丟棄不拋異常DiscardPolicy
3.丟棄最前邊的任務(wù)執(zhí)行最新的任務(wù)DiscardOldestPolicy
4.由調(diào)用線程執(zhí)行該任務(wù)CallerRunsPolicy線程生命周期
新建(New)、就緒(Runnable)、運(yùn)行(Running)、阻塞(Blocked)和死亡(Dead)五種狀態(tài)
當(dāng)創(chuàng)建Thread類的一個(gè)實(shí)例(對象)時(shí) t=new Thread(),此線程進(jìn)入新建狀態(tài)(未被啟動(dòng))。
t.start().線程已經(jīng)被啟動(dòng),正在等待被分配給CPU時(shí)間片,也就是說此時(shí)線程正在就緒隊(duì)列中排隊(duì)等候得到CPU資源
t.run()運(yùn)行synchronized原理
由jvm字節(jié)碼中可以看到ACC_SYNCHRONIZED,對同步塊使用了monitorenter和monitorexit指令,隱式的實(shí)現(xiàn)了lock,unlock。jdk對synchronized做了哪些優(yōu)化
jdk1.6對鎖做了優(yōu)化,在對象頭中包含了輕量鎖,重量鎖,偏向鎖。
synchronized使用的鎖對象是存儲(chǔ)在Java對象頭里。它是輕量級鎖和偏向鎖的關(guān)鍵,偏向線程ID指向自己
https://www.cnblogs.com/wuzhenzhao/p/10250801.htmlReentrantLock
ReentrantLock是可重入的獨(dú)占鎖。比起synchronized功能更加豐富,支持公平鎖實(shí)現(xiàn),支持中斷響應(yīng)以及限時(shí)等待等等。可以配合一個(gè)或多個(gè)Condition條件方便的實(shí)現(xiàn)等待通知機(jī)制。CAS、ABA問題
CAS樂觀鎖操作,Compare and Swap 這是一個(gè)重量鎖的實(shí)現(xiàn)。
ABA A改為B又改為A,這種問題使用版本號控制解決。J.U.C java.util.concurrent。
CompareAndSet 利用Unsafe類的JNI方法實(shí)現(xiàn)CAS,無鎖算法
https://segmentfault.com/a/1190000015558984
基礎(chǔ)
- ArrayList和LinkedList
ArrayList是實(shí)現(xiàn)了基于動(dòng)態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu),LinkedList是基于鏈表結(jié)構(gòu)。
modCount是ArrayList中的一個(gè)成員變量。 - 什么是fail—fast?
快速失效系統(tǒng),先考慮異常情況,一旦發(fā)現(xiàn)異常立馬終止。業(yè)務(wù)設(shè)計(jì)接口檢測拋出異常就是這個(gè)東西。還有一種是指Java集合的一種錯(cuò)誤檢測機(jī)制,當(dāng)多個(gè)線程對部分集合進(jìn)行結(jié)構(gòu)上的改變的操作時(shí),有可能會(huì)產(chǎn)生fail-fast機(jī)制,這個(gè)時(shí)候就會(huì)拋出ConcurrentModificationException。 - HashMap的put、擴(kuò)容原理,1.7和1.8的數(shù)據(jù)結(jié)構(gòu)


1.7 hashmap 數(shù)組+鏈表
1.8 數(shù)組+鏈表+紅黑樹 鏈表長度大于8轉(zhuǎn)為紅黑樹



為何鏈表長度為8,hashcode之后的頻率遵循泊松分布,泊松分布對照表中鏈表為8的概率非常小。
- HashMap并發(fā)問題
主要出在擴(kuò)容階段,當(dāng)兩個(gè)線程同時(shí)resize時(shí)鏈表會(huì)成環(huán)狀鏈表,當(dāng)調(diào)用get時(shí)會(huì)陷入死循環(huán)。 - TCP粘包,為什么出現(xiàn),如何解決?
tcp為提高性能,發(fā)送端會(huì)將需要發(fā)送的數(shù)據(jù)發(fā)送到緩沖區(qū),等待緩沖區(qū)滿了之后,再將緩沖中的數(shù)據(jù)發(fā)送到接收方。同理,接收方也有緩沖區(qū)這樣的機(jī)制,來接收數(shù)據(jù)。
約定數(shù)據(jù)包長度這樣可以清晰的獲取到我們需要的數(shù)據(jù);使用分隔符;每個(gè)數(shù)據(jù)包的開頭利用2個(gè)或者4個(gè)字節(jié)填充整個(gè)數(shù)據(jù)包的長度 - TCP如何實(shí)現(xiàn)消息可靠性、滑動(dòng)窗口
TCP確認(rèn)重傳機(jī)制,滑動(dòng)窗口為TCP不是每一段報(bào)文都進(jìn)行ACK,如果接收方期望的報(bào)文一直沒來,其他的報(bào)文則會(huì)放入滑動(dòng)窗口緩沖區(qū)。 - TCP三次握手四次揮手
1.客戶端首先要SYN=1,表示要?jiǎng)?chuàng)建連接,
2.服務(wù)端接收到后,要告訴客戶端:我接受到了!所以加個(gè)ACK=1,就變成了ACK=1,SYN=1
3.理論上這時(shí)就創(chuàng)建連接成功了,但是要防止一個(gè)意外(重試多次建立連接問題),所以客戶端要再發(fā)一個(gè)消息給服務(wù)端確認(rèn)一下,這時(shí)只需要ACK=1就行了。
在四次揮手時(shí),
1.首先客戶端請求關(guān)閉客戶端到服務(wù)端方向的連接,這時(shí)客戶端就要發(fā)送一個(gè)FIN=1,表示要關(guān)閉一個(gè)方向的連接
2.服務(wù)端接收到后是需要確認(rèn)一下的,所以返回了一個(gè)ACK=1
3.這時(shí)只關(guān)閉了一個(gè)方向,另一個(gè)方向也需要關(guān)閉,所以服務(wù)端也向客戶端發(fā)了一個(gè)FIN=1 ACK=1
4.客戶端接收到后發(fā)送ACK=1,表示接受成功 - 事務(wù)的隔離級別、mysql和oracle默認(rèn)是什么,都解決了什么問題
read uncommitted 未提交讀 所有事務(wù)都可以看到?jīng)]有提交事務(wù)的數(shù)據(jù)。
read committed 提交讀 事務(wù)成功提交后才可以被查詢到。
repeatable 重復(fù)讀 同一個(gè)事務(wù)多個(gè)實(shí)例讀取數(shù)據(jù)時(shí),可能將未提交的記錄查詢出來,而出現(xiàn)幻讀。mysql默認(rèn)級別
Serializable可串行化 強(qiáng)制的進(jìn)行排序,在每個(gè)讀讀數(shù)據(jù)行上添加共享鎖。會(huì)導(dǎo)致大量超時(shí)現(xiàn)象和鎖競爭。 - 事務(wù)的特性
ACID-原子性 一致性 隔離性 持久性 - 快照讀和當(dāng)前讀
快照讀 即讀取數(shù)據(jù)的可見版本,數(shù)據(jù)可能是歷史數(shù)據(jù)。主要通過MVCC(多版本控制)和undo log 來實(shí)現(xiàn),優(yōu)勢是不加鎖,并發(fā)性高。缺點(diǎn)是不是實(shí)時(shí)數(shù)據(jù)
當(dāng)前讀 是通過加record lock(記錄鎖)和gap lock(間隙鎖)來實(shí)現(xiàn)的 (select ... for update)
InnoDB為每行記錄添加了一個(gè)事務(wù)ID,每當(dāng)修改數(shù)據(jù)時(shí),將當(dāng)事務(wù)ID寫入。 - 樂觀鎖、悲觀鎖、間隙鎖、行鎖、表鎖的使用場景
樂觀鎖 讀的時(shí)候不加鎖,只有在更新的時(shí)候判斷版本號進(jìn)行更新
悲觀鎖 讀的時(shí)候就加上鎖
間隙鎖 當(dāng)我們用范圍條件檢索數(shù)據(jù),并請求共享或排他鎖時(shí),InnoDB會(huì)給符合范圍條件的已有數(shù)據(jù)記錄的索引項(xiàng)加鎖;對于鍵值在條件范圍內(nèi)但并不存在的記錄,叫做“間隙(GAP)”。InnoDB也會(huì)對這個(gè)“間隙”加鎖
行鎖 鎖顆粒度為行級
表鎖 表共享讀鎖(Table Read Lock)和表獨(dú)占寫鎖(Table Write Lock)
B數(shù) B+樹、聚簇索引和非聚簇索引
B數(shù)為多叉數(shù),和平衡二叉樹不同的是搜索路徑不止兩條,同樣遵循左小右大原則
B+樹 B+的搜索與B-樹也基本相同,區(qū)別是B+樹只有達(dá)到葉子結(jié)點(diǎn)才命中(B-樹可以在
非葉子結(jié)點(diǎn)命中)
B+的特性:
1.所有關(guān)鍵字都出現(xiàn)在葉子結(jié)點(diǎn)的鏈表中(稠密索引),且鏈表中的關(guān)鍵字恰好
是有序的;
2.不可能在非葉子結(jié)點(diǎn)命中;
3.非葉子結(jié)點(diǎn)相當(dāng)于是葉子結(jié)點(diǎn)的索引(稀疏索引),葉子結(jié)點(diǎn)相當(dāng)于是存儲(chǔ)
(關(guān)鍵字)數(shù)據(jù)的數(shù)據(jù)層;
4.更適合文件索引系統(tǒng);
B*樹:在B+樹基礎(chǔ)上,為非葉子結(jié)點(diǎn)也增加鏈表指針,將結(jié)點(diǎn)的最低利用率
從1/2提高到2/3;
聚簇索引 innodb中根據(jù)主鍵生成B+樹,葉子節(jié)點(diǎn)存儲(chǔ)的是行記錄數(shù)據(jù),也將聚集索引的葉子節(jié)點(diǎn)稱為數(shù)據(jù)頁。
非聚簇索引 在聚簇索引之上創(chuàng)建的索引稱之為輔助索引,輔助索引訪問數(shù)據(jù)總是需要二次查找。輔助索引葉子節(jié)點(diǎn)存儲(chǔ)的不再是行的物理位置,而是主鍵值
MyISAM索引文件和數(shù)據(jù)文件是分離的,索引文件僅保存數(shù)據(jù)記錄的地址。而在InnoDB中,表數(shù)據(jù)文件本身就是按B+Tree組織的一個(gè)索引結(jié)構(gòu) - mvcc多版本并發(fā)控制
在每一行數(shù)據(jù)會(huì)隱藏式創(chuàng)建兩個(gè)列。行創(chuàng)建時(shí)的版本號和刪除時(shí)的版本號。
每行數(shù)據(jù)都存在一個(gè)版本,每次數(shù)據(jù)更新時(shí)都更新該版本。修改時(shí)Copy出當(dāng)前版本隨意修改,各個(gè)事務(wù)之間無干擾。保存時(shí)比較版本號,如果成功(commit),則覆蓋原記錄;失敗則放棄copy(rollback) - redolog、undolog、binlog
redolog 重做日志 是每個(gè)數(shù)據(jù)在更新時(shí)將更新記錄到redo日志中,定時(shí)刷入磁盤。
和undolo同屬于事務(wù)日志,不同的是redo是前滾日志。保證了事務(wù)的持久性
undolog 回滾日志,保存了事務(wù)數(shù)據(jù)更新前一個(gè)數(shù)據(jù),保證了事務(wù)的原子性。
binlog 歸檔日志,主要用于主從復(fù)制,記錄了相關(guān)sql記錄。 - 索引失效的場景
1.有 or 的
2.like 前綴%
3.字符串值為數(shù)字,不加單引號的
4.聯(lián)合索引不按順序
5.不要對索引列進(jìn)行聚合函數(shù)操作 - Redis數(shù)據(jù)類型,底層數(shù)據(jù)結(jié)構(gòu)
string hash list set zset bitmap hyteloglog geo stream - 緩存穿透、緩存擊穿 緩存雪崩
查詢一個(gè)不存在的key ,緩存null,布隆過濾器
key 過期后大量的請求打在db上,db查詢加鎖及限流
緩存雪崩 大量的key同一時(shí)間過期,隨機(jī)時(shí)間 - mysql和redis 一致性問題
給緩存設(shè)置合理的過期時(shí)間,或者進(jìn)行補(bǔ)償。或者使用阿里開源canal ,對mysql的binlog進(jìn)行訂閱,對redis在進(jìn)行處理。
spring
- IOC和AOP的理解及原理
IOC就是典型的工廠模式,由sessionFactory去注入實(shí)例。通過IOC容器可以將依賴的對象創(chuàng)建等交給spring去處理
AOP就是面向切面編程,分離關(guān)注點(diǎn)。動(dòng)態(tài)代理和靜態(tài)織入 - Bean的生命周期
大概分為9步:
1,實(shí)例化bean對象
2.設(shè)置對象屬性
3.如果bean實(shí)現(xiàn)了beanNameAware則將會(huì)將bean的ID進(jìn)行傳遞
4.如果bean實(shí)現(xiàn)了beanfatoryAware則傳遞工廠
5.調(diào)用bean的前置處理器
6,bean的初始化
7.調(diào)用bean的后置處理器
8.使用bean
9.銷毀bean - 自動(dòng)注入方式有哪些,兩個(gè)注解的區(qū)別
@Autowired 基于bytype的注入,默認(rèn)對象必須是存在的,是spring提供的注解
@Resource 基于byname的注入,默認(rèn)對象可為null 是J2EE提供的注解
@Inject 先基于name查找沒有則使用類型查找 -
MVC流程
image.png - 分布式事務(wù)怎么做的
1.XA saga TCC seata
XA 兩階段提交 性能有問題 并不是所有資源都支持XA協(xié)議
saga 基于應(yīng)用共享事務(wù)記錄執(zhí)行軌跡;然后通過異步重試確保交易最終一致
TCC 的特點(diǎn)在于業(yè)務(wù)資源檢查與加鎖,一階段進(jìn)行校驗(yàn),資源鎖定,如果第一階段都成功,二階段對鎖定資源進(jìn)行交易邏輯,否則,對鎖定資源進(jìn)行釋放。應(yīng)用實(shí)施成本較高。
Seata架構(gòu)的亮點(diǎn)主要有幾個(gè):
應(yīng)用層基于SQL解析實(shí)現(xiàn)了自動(dòng)補(bǔ)償,從而最大程度的降低業(yè)務(wù)侵入性;
將分布式事務(wù)中TC(事務(wù)協(xié)調(diào)者)獨(dú)立部署,負(fù)責(zé)事務(wù)的注冊、回滾;
通過全局鎖實(shí)現(xiàn)了寫隔離與讀隔離。 - CAP、BASE理論
CAP原則又稱CAP定理,指的是在一個(gè)分布式系統(tǒng)中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區(qū)容錯(cuò)性),三者不可得兼。zk是CP,eurka是AP.
BASE是對CAP中一致性和可用性權(quán)衡的結(jié)果,其來源于對大規(guī)模互聯(lián)網(wǎng)系統(tǒng)分布式實(shí)踐的結(jié)論,是基于CAP定理逐步演化而來的,其核心思想是即使無法做到強(qiáng)一致性(Strong consistency),但每個(gè)應(yīng)用都可以根據(jù)自身的業(yè)務(wù)特點(diǎn),采用適當(dāng)?shù)姆绞絹硎瓜到y(tǒng)達(dá)到最終一致性(Eventual consistency)。 - 高并發(fā)之服務(wù)降級和服務(wù)熔斷
犧牲局部,保全整體的措施 - 令牌桶、漏桶、滑動(dòng)窗口算法
控制數(shù)據(jù)注入到網(wǎng)絡(luò)的速率,平滑網(wǎng)絡(luò)上的突發(fā)流量 - 分布式id如何生成
1.主鍵自增
2.redis
3.雪花算法
4,leaf 緩存一個(gè)號段 雙buffer
JVM
- 共享內(nèi)存區(qū)
程序計(jì)數(shù)器
Java虛擬機(jī)棧
本地方法棧
Java堆
方法區(qū) -
幾種OOM
image.png - 類加載機(jī)制
JVM類加載機(jī)制分為五個(gè)部分:加載,驗(yàn)證,準(zhǔn)備,解析,初始化 - 雙親委派機(jī)制
如果一個(gè)類加載器收到了類加載器的請求.它首先不會(huì)自己去嘗試加載這個(gè)類.而是把這個(gè)請求委派給父加載器去完成.每個(gè)層次的類加載器都是如此.因此所有的加載請求最終都會(huì)傳送到Bootstrap類加載器(啟動(dòng)類加載器)中.只有父類加載反饋?zhàn)约簾o法加載這個(gè)請求(它的搜索范圍中沒有找到所需的類)時(shí).子加載器才會(huì)嘗試自己去加載。
雙親委派模型的優(yōu)點(diǎn):java類隨著它的加載器一起具備了一種帶有優(yōu)先級的層次關(guān)系. - 新生代默認(rèn)多少次晉升老年代
MaxTenuringThreshold 默認(rèn)為15,并不是指15次gc晉升,有動(dòng)態(tài)閾值調(diào)整

