JAVA在大型機(jī)時(shí)代就專注于多線程,火到線程也完全得益于原生多線程的強(qiáng)大。多線程必然帶來(lái)一個(gè)問(wèn)題,資源的同步問(wèn)題。java有很多同步手段,但是追根到底就是CAS與AQS
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? CAS
CAS就是CompareAndSwap,翻譯過(guò)來(lái)就是:比較與替換,預(yù)期值與內(nèi)存值比較,true就更新新值,false就不進(jìn)行任何操作,這是個(gè)死循環(huán),比較的過(guò)程會(huì)一直執(zhí)行。舉個(gè)例子:

其中flag.compareAndSet(true,false)的返回值為true就是獲得到了鎖,并且把flag的值置為false,所以內(nèi)存中的值變?yōu)閒alse,下個(gè)搶購(gòu)線程來(lái)臨時(shí),整個(gè)在進(jìn)行flag.compareAndSet(true,false)時(shí),返回值就變?yōu)閒asle,返回?fù)屬?gòu)失敗。直到上一個(gè)線程把flag把值重新置為fasle,才能搶購(gòu)成功。
當(dāng)然,如果搶購(gòu)非常激烈的話,CAS(本質(zhì)上是樂(lè)觀鎖)性能不一定比Sync好,說(shuō)穿了就是占著線程不還,在死循環(huán),避免內(nèi)核態(tài)用戶態(tài)線程切換導(dǎo)致的性能損耗,但是如果競(jìng)爭(zhēng)太過(guò)激烈,死循環(huán)也拿不到執(zhí)行權(quán),會(huì)導(dǎo)致CPU性能的浪費(fèi)。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AQS
AQS就是AbstractQueuedSynchronizer,常見(jiàn)的ReentrantLock,Semaphare,CounDownLatch等等同步類,實(shí)現(xiàn)都靠他。
AQS實(shí)際就三個(gè)元素 ,被執(zhí)行的資源狀態(tài),當(dāng)前執(zhí)行者,后面排隊(duì)等著的執(zhí)行者。
被執(zhí)行資源狀態(tài):要不就是0,要不是1,要不比1大。0的時(shí)候代表沒(méi)線程執(zhí)行,1的時(shí)候說(shuō)明被執(zhí)行了,比1大代表被重入了(就是被當(dāng)前的執(zhí)行者反復(fù)來(lái)回的獲得執(zhí)行權(quán))。
當(dāng)前執(zhí)行者:就是取得被執(zhí)行資源的執(zhí)行權(quán),可重入,除非把資源釋放,后面等著的執(zhí)行者獲取不到執(zhí)行權(quán)(需要一直釋放到0)
后面的排隊(duì)等待著:一個(gè)雙向隊(duì)列,其中的節(jié)點(diǎn)在自旋等待執(zhí)行權(quán),抄襲一張圖(來(lái)自https://www.cnblogs.com/waterystone/p/4920797.html)。

這張圖基本是對(duì)的,最后的成為節(jié)點(diǎn)成隊(duì)頭有點(diǎn)問(wèn)題,實(shí)際一旦等待著獲得執(zhí)行權(quán)就會(huì)彈出雙向隊(duì)列,并不在等待隊(duì)列中。