一: synchronized的執(zhí)行過程: 偏向鎖->輕量級自旋鎖->重量級鎖
檢測Mark Word里面是不是當前線程的ID菠发,如果是,表示當前線程處于偏向鎖
如果不是钞它,則使用CAS將當前線程的ID替換Mard Word蔑担,如果成功則表示當前線程獲得偏向鎖,置偏向標志位1
如果失敗章贞,則說明發(fā)生競爭,撤銷偏向鎖非洲,進而升級為輕量級鎖鸭限。
當前線程使用CAS將對象頭的Mark Word替換為鎖記錄指針蜕径,如果成功,當前線程獲得鎖
如果失敗败京,表示其他線程競爭鎖兜喻,當前線程便嘗試使用自旋來獲取鎖。
如果自旋成功則依然處于輕量級狀態(tài)赡麦。
如果自旋失敗朴皆,則升級為重量級鎖。
首先試圖加偏向鎖,修改對象頭的線程id,如果失敗,說明存在競爭,進而使用輕量級鎖進行自旋獲取鎖,自旋失敗泛粹,則升級為重量級鎖
二: 鎖的類型
- 公平鎖和非公平鎖
公平鎖是嚴格按照請求所的順序來排隊獲得鎖的遂铡,而非公平鎖時可以搶占的
-
輕量級鎖和重量級鎖
輕量級自旋 不進行操作系統(tǒng)用戶態(tài)和內核態(tài)的轉換,消耗cpu;重量級鎖相反
讀寫鎖和互斥鎖
-
悲觀鎖和樂觀鎖
悲觀鎖:假定會發(fā)生并發(fā)沖突,屏蔽一切可能違反數據完整性的操作戚扳。 樂觀鎖:假定不會發(fā)生并發(fā)沖突忧便,只在提交操作時檢測是否違反數據完整性。(使用版本號或者時間戳來配合實現)
-
可重入鎖 ReentrantLock
通俗來說:當線程請求一個由其它線程持有的對象鎖時帽借,該線程會阻塞珠增,而當線程請求由自己持有的對象鎖時,如果該鎖是重入鎖砍艾,請求就會成功蒂教,否則阻塞。
實現原理:每一個鎖關聯(lián)一個線程持有者和計數器脆荷,當計數器為 0 時表示該鎖沒有被任何線程持有凝垛,那么任何線程都可能獲得該鎖而調用相應的方法;當某一線程請求成功后蜓谋,JVM會記下鎖的持有線程梦皮,并且將計數器置為 1;此時其它線程請求該鎖桃焕,則必須等待剑肯;而該持有鎖的線程如果再次請求這個鎖,就可以再次拿到這個鎖观堂,同時計數器會遞增让网;當線程退出同步代碼塊時,計數器會遞減师痕,如果計數器為0溃睹,則釋放該鎖。
三: 分布式標識 實現的冪等 VS 鎖
標識: 根據標識決定是否執(zhí)行,無法執(zhí)行可以返回也可以自旋等待
鎖: 對象,資源;
思考:多個請求 可能相同id,可能不同id,要求相同id順序執(zhí)行,不同id可以并發(fā)??(不是鎖對象,而是根據標識判斷執(zhí)行邏輯)
使用id作為標識位來實現,存儲了該標識則阻塞等待
所以 冪等:拿到標識執(zhí)行,拿不到則返回不執(zhí)行(可以不做)
鎖:拿到標識執(zhí)行,拿不到則阻塞或者自旋等待執(zhí)行(必須要做)
四: 死鎖
互斥條件:一個資源每次只能被一個進程使用胰坟。
請求與保持條件:一個進程因請求資源而阻塞時因篇,對已獲得的資源保持不放。
不剝奪條件:進程已獲得的資源,在未使用完之前惜犀,不能強行剝奪铛碑。
循環(huán)等待條件:若干進程之間形成一種頭尾相接的循環(huán)等待資源關系狠裹。
概括:一個資源每次只能被一個線程;線程沒使用完之前,不能剝奪;線程請求其他資源,不會放棄已獲取的資源;線程間為等待資源形成循環(huán)
避免死鎖: 預防 與 后置處理
避免死鎖最簡單的方法就是阻止循環(huán)等待條件虽界,將系統(tǒng)中所有的資源設置標志位、排序涛菠,規(guī)定所有的進程申請資源必須以一定的順序做操作來避免死鎖(阻止循環(huán)等待條件,資源排序按順序獲取)
五: CAS AQS(AbstractQueuedSynchronizer類:抽象隊列同步器)
AQS: state ThreadId FIFO
-
獲取鎖的過程:
當線程調用acquire()申請獲取鎖資源莉御,如果成功,則進入臨界區(qū)俗冻。
當獲取鎖失敗時礁叔,則進入一個FIFO等待隊列,然后被掛起等待喚醒迄薄。
當隊列中的等待線程被喚醒以后就重新嘗試獲取鎖資源琅关,如果成功則進入臨界區(qū),否則繼續(xù)掛起等待讥蔽。
-
釋放鎖過程:
當線程調用release()進行鎖資源釋放時涣易,如果沒有其他線程在等待鎖資源,則釋放完成冶伞。
如果隊列中有其他等待鎖資源的線程需要喚醒新症,則喚醒隊列中的第一個等待節(jié)點(先入先出)。(釋放鎖時去喚醒隊列中的阻塞線程嘗試獲取鎖**)