Reent和Synchronize區(qū)別
ReentrantLock和Synchronize都是一個可重入鎖
區(qū)別在于ReentrantLock是jdk提供的一個鎖泽本,它有一下Synchronize不具備的特性,比如鎖中斷暖璧,鎖多個對象通過Condition酱畅,公平鎖。它有兩個內(nèi)部類江场,F(xiàn)airSync纺酸,和NoFairSync,都間接繼承了AbstractQueuedSynchronizer同步隊列類,使用AQS實現(xiàn)了加鎖和解鎖的功能址否。
AQS是J.U.C包的基礎(chǔ)組件餐蔬,是實現(xiàn)一系列并發(fā)工具的基礎(chǔ)碎紊。
它里面提供了一個阻塞隊列(鏈表實現(xiàn)的)來保存沒有獲取到鎖的線程,每一個節(jié)點如何保存當前線程和前后節(jié)點的引用之外還需要保存一個waitStatus樊诺,表示節(jié)點的狀態(tài)仗考。提供了一個狀態(tài)變量state,表示鎖的狀態(tài)词爬。其中大量使用了CAS操作秃嗜。
當A,B線程進行競爭的時候顿膨,
1锅锨、A線程通過CAS操作修改statue成功,說明A競爭到了鎖恋沃,繼續(xù)執(zhí)行
2必搞、如果A操作失敗,說明B獲取了鎖囊咏,那么A執(zhí)行下面的流程
3恕洲、生成一個新節(jié)點,通過CAS操作插入到隊尾梅割,并且它不會立即掛起霜第,而是執(zhí)行自旋,因為插入到隊尾的這段時間炮捧,B可能已經(jīng)執(zhí)行完了釋放了鎖了庶诡,所以判斷當前節(jié)點的前一個節(jié)點是不是head節(jié)點,如果是的話咆课,嘗試獲取鎖末誓,獲取成功,那么就不掛起了书蚪,直接執(zhí)行喇澡。如果失敗或者不是head節(jié)點,執(zhí)行下一步殊校。
4晴玖、判斷前一個節(jié)點的狀態(tài)是不是SIGNAL,只有是SINGNAL的時候才會掛起为流。如果前一個節(jié)點的waitStatus==0呕屎,那么通過CAS操作將狀態(tài)改成SINGNAL,如果waitSatus > 0 說明是CANCELLED的狀態(tài)敬察,刪除這個節(jié)點秀睛,如果waitStatus==SIGNAL,那么調(diào)用LockSupport.park()方法掛起莲祸。
5蹂安、釋放鎖的時候從隊列里找到第一個SIGNAL狀態(tài)的節(jié)點喚醒椭迎,喚醒的線程需要判斷是否中斷,需要和新來的線程進行競爭鎖田盈,這體現(xiàn)了非公平性畜号。
Synchronize是JVM提供的一個關(guān)鍵字,是一個可重入鎖允瞧,通過在需要同步的字節(jié)碼前后加上monitorenter和monitorexit简软,當線程執(zhí)行到monitorenter的時候就需要去獲取對象的鎖,如果獲取成功了瓷式,就繼續(xù)執(zhí)行替饿,失敗了就阻塞。也維護了一個計數(shù)器來記錄重入次數(shù)贸典。不過現(xiàn)在對這個Synchronize優(yōu)化的比較好了视卢,引入了自旋鎖,適應性自旋廊驼,輕量級鎖据过,偏向鎖,鎖粗化妒挎,鎖消除等等绳锅,提高了synchronize性能。
輕量級鎖酝掩,為了在有并發(fā)但是沒有競爭的情況下替代重量級鎖鳞芙,減少系統(tǒng)消耗,操作的核心是對象頭的Mark Word期虾,這塊區(qū)域平時保存的是hashCode原朝,gc年齡等。
當一個線程準備后去輕量級鎖的時候镶苞,先判斷他有沒有被鎖定喳坠,如果沒有鎖定,那么會在棧幀里面創(chuàng)建一塊內(nèi)存區(qū)域茂蚓,復制這個markword壕鹉,然后通過cas操作將原來的MarkWord更改成執(zhí)行棧幀中的指針,狀態(tài)改成輕量級鎖定聋涨。成功說明獲取到了輕量級鎖晾浴,失敗說明發(fā)生了競爭,需要膨脹成重量級鎖牍白,后面的線程全部阻塞脊凰。
釋放鎖的時候,將棧幀中的MarkWord更新回去淹朋,如果成功笙各,就成功釋放,如果失敗础芍,說明有別的線程競爭杈抢,釋放鎖的同時需要喚醒被掛起的線程。