終于把Java鎖分類理清楚了
1.內置鎖與顯式鎖
開發人員根據書寫方式將鎖分為內置鎖和顯式鎖,這個分類純粹是因為Java中的鎖分為兩大派:老派鎖和新派鎖。synchronized一人開一派,曾獨占鰲頭數十載,是老派鎖的代表,新派則是以AQS為首新興門派,其子子孫孫遍布并發編程的各個角落。
synchronized在書寫上只需要在方法名或者靜態代碼塊中聲明synchronized關鍵字即可,其加鎖,釋放鎖均是由程序自行處理,因而得名內置鎖。
而新派鎖AQS門下的鎖基本都是需要手動聲明加鎖和釋放鎖的,如果程序員忘記寫釋放鎖的代碼就會造成鎖永遠不會釋放,其門下應用最多且與synchronized能對等換的當屬如ReentrantLock,因為有了顯式鎖的說法。
內置鎖不需要程序員操心上鎖和釋放鎖的邏輯,但是在應用靈活度上有些欠缺,比如說控制鎖的范圍,內置鎖就不能很好的縮小鎖范圍。
顯示鎖因為其需要手動加鎖和釋放鎖,所以具備更高的控制加鎖范圍的靈活性。因為其鎖的實現是在Java層面實現,作為Java開發者可以靈活優化其功能,所以其功能可以更多,而synchronized是由jvm層面實現,作為Java開發者就沒有辦法修改到jvm底層所以功能上會有局限性。
2. 可重入鎖與不可重入鎖
我們知道當前線程獲取到鎖后,另外的線程就獲取不到這把鎖,那么當前線程如果再次獲取這把鎖的時候,是否能獲取到呢,如果能獲取到就是可重入鎖,如果獲取不到就是不可重入鎖,即是否可重入說的是線程自己是否能夠多次獲取鎖。
這里需要注意的是可重入鎖,重入幾次,釋放鎖的時候也要釋放幾次,synchronized和ReentrantLock是可重入鎖,且新派鎖中作為aqs的子子孫孫很容易實現不可重入的鎖,程序員也可以手動根據可重入鎖實現不可重入鎖。但是在Java中基本沒有提供現成的不可重入鎖實現類。
3. 公平鎖與非公平鎖
顧名思義,公平不公平就是大家是否有秩序的去競爭鎖資源,何為有秩序,那就是排隊唄,講究先來后到。
老派鎖的代表synchronized是一個實打實的非公平鎖,它的非公平是說沒有搶到鎖的線程都會被阻塞并放到某個集合中,這個集合是jvm底層實現,我們暫不關心,當占有鎖的線程釋放鎖后,jvm會在這個集合中隨機喚醒一個去獲取鎖,這里的非公平重在隨機。
我們說了新派鎖是基于AQS,所以其子孫后代鎖在功能上會有更高的靈活性。以ReentrantLock為例,它默認情況下是非公平鎖,但是可以通過傳參實現公平鎖。其非公平和老派鎖有點不一樣,例如,線程1獲取了鎖后,線程2 線程3因為獲取不到鎖而進入阻塞隊列進行排隊阻塞,當有線程4試圖獲取鎖資源的時候,如果聲明的是公平鎖,線程4會直接進入隊列排隊,如果聲明的是非公平鎖,線程4會直接搶鎖,即這里的非公平說的是新進來的線程與阻塞隊列頭部的線程爭奪鎖資源,強調的是新線程與隊列老大的競爭。
新老派鎖的非公平都會不同成都的造成,某些或則某個線程一直拿不到鎖,但是似乎老派鎖synchronized造成這種現象的概率大一點。
4.共享鎖與獨占鎖
既然是鎖,那一定是某些線程不能進入,但是哪些線程能進入,就造就了共享鎖和獨占鎖的區分,顧名思義,只允許一個線程獨享的鎖就是獨占鎖,允許多個線程共同進入的鎖就是共享鎖。
老派鎖synchronized和新派鎖ReentrantLock都是獨占鎖,而新派鎖AQS門下,有一些鎖是共享鎖,例如:ReentrantReadWriteLock,Semaphore,CountDownLatch,CyclicBarrier等
5. 樂觀鎖與悲觀鎖
鎖的作用就是將某段業務邏輯保護起來,更深一點就是將邏輯中共享數據保護起來,防止多個線程操作共享數據的時候出現問題。然而開發者根據鎖的情感態度將鎖分為樂觀鎖和悲觀鎖,我們上面說的老派鎖和新派鎖,他們都對共享數據的保護持悲觀態度,他們認為所有的線程都有可能侵害共享數據,因此早早在業務邏輯前加上鎖,每來一個線程都要進行排查。并且只允許一個線程進入。所以他們都是悲觀鎖。
然而就在新派鎖崛起的同一時期,遙遠的北方有一支異軍突起,他們劍走偏鋒,他們認為所有人在沒有露出魔鬼爪牙前都是好人,他們持一種樂觀的態度對待共享數據的保護,但是他們并不是不保護,只是保護的方式是,當某個線程對共享數據操作前,必須先獲取一個令牌,然后拿著令牌去操作共享數據,當共享數據保存的令牌與整個線程持有的令牌匹配正確后才能操作。如果匹配不上就操作失敗。
在操作數據失敗后應該怎么操作,就需要開發者自行處理,或者直接返回失敗信息,或者再次重試,一般情況下,樂觀鎖會結合自旋重試來使用,但是當并發很高的時候,會造成很多線程自旋,給cpu帶來壓力,所以適用的場景有限。
總結
鎖,是排他的一種機制,排他性是鎖的統一標準,而根據其排他的積極程度,分為樂觀鎖和悲觀鎖,而悲觀鎖又分為兩大派系,一個是以synchronized為首的老派鎖,一個是以AQS為首的新派鎖。
而公平與非公平,可重入與不可重入,共享與獨占,內置與顯式,可中斷與不可中斷都是鎖的特性。
接下來就分開來介紹其底層實現。