一、宏觀的說下鎖的分類
1)鎖分為樂觀鎖、悲觀鎖
悲觀鎖認為對于同一個數據的并發操作,一定是會發生修改的,哪怕沒有修改,也會認為修改。因此對于同一個數據的并發操作,悲觀鎖采取加鎖的形式。悲觀的認為,不加鎖的并發操作一定會出問題。
樂觀鎖則認為對于同一個數據的并發操作,是不會發生修改的。在更新數據的時候,會采用嘗試更新,不斷重新的方式更新數據。樂觀的認為,不加鎖的并發操作是沒有事情的
2)鎖分為公平鎖、非公平鎖
公平鎖是指多個線程按照申請鎖的順序來獲取鎖。
非公平鎖是指多個線程獲取鎖的順序并不是按照申請鎖的順序,有可能后申請的線程比先申請的線程優先獲取鎖。有可能,會造成優先級反轉或者饑餓現象。
?
3)鎖分為獨享鎖、共享鎖
獨享鎖是指該鎖一次只能被一個線程所持有。
共享鎖是指該鎖可被多個線程所持有。
?
?
?
?
二、java中常見具體高并發鎖
1)synchronized
synchronized機制是給共享資源上鎖,只有拿到鎖的線程才可以訪問共享資源,這樣就可以強制使得對共享資源的訪問都是順序的,夠保證在同一個時刻最多只有一個線程執行同一個對象的同步代碼,可保證修飾的代碼在執行過程中不會被其他線程干擾
synchronized(obj) {}
synchronized實現的機理依賴于軟件層面上的JVM,對于Synchronized而言,也是一種悲觀鎖、非公平鎖、也是獨享鎖、也是互斥鎖。
?
?
2)ReentrantLock
可重入鎖,顧名思義,這個鎖可以被線程多次重復進入進行獲取操作
Lock實現的機理依賴于特殊的CPU指令,比如執行lock()方法的時候,cpu發出lock指令,比如我們執行unlock的時候,cpu發出lock指令,可以認為不受JVM的約束,并可以通過其他語言平臺來完成底層的實現。在并發量較小的多線程應用程序中,ReentrantLock與synchronized性能相差無幾,但在高并發量的條件下,synchronized性能會迅速下降幾十倍,而ReentrantLock的性能卻能依然維持一個水準,高并發量情況下使用ReentrantLock。
ReentrantLock通過方法lock()與unlock()來進行加鎖與解鎖操作,與synchronized會被JVM自動解鎖機制不同,ReentrantLock加鎖后需要手動進行解鎖。為了避免程序出現異常而無法正常解鎖的情況,使用ReentrantLock必須在finally控制塊中進行解鎖操作。通常使用方式如下所示
Lock lock = new ReentrantLock();try {lock.lock();}finally {lock.unlock();}
對于ReentrantLock而言,ReentrantLock在構造函數中提供了是否公平鎖的初始化方式,默認為非公平鎖。這是因為,非公平鎖實際執行的效率要遠遠超出公平鎖、ReentrantLock也是互斥鎖、也是獨享鎖。
?
?
3)Semaphore
互斥是進程同步關系的一種特殊情況,相當于只存在一個臨界資源,因此同時最多只能給一個線程提供服務。但是,在實際復雜的多線程應用程序中,可能存在多個臨界資源,這時候我們可以借助Semaphore信號量來完成多個臨界資源的訪問
,通過acquire()與release()方法來獲得和釋放臨界資源,Semaphore和ReentrantLock用法差不多,Semaphore的鎖釋放操作也由手動進行,因此與ReentrantLock一樣,為避免線程因拋出異常而無法正常釋放鎖的情況發生,釋放鎖的操作也必須在finally代碼塊中完成,
構造方法里面也可以設置否公平鎖的初始化方式,默認為非公平鎖。
?
?
4)AtomicInteger
在多線程程序中,諸如++i或i++等運算不具有原子性,是不安全的線程操作之一。通常我們會使用synchronized將該操作變成一個原子操作,但JVM為此類操作特意提供了一些同步類,使得使用更方便,且使程序運行效率變得更高。通常AtomicInteger的性能是ReentantLock的好幾倍。
?
?
?
?
三、各個鎖的優勢
1.synchronized:
在資源競爭不是很激烈的情況,偶爾會有同步的情形下,synchronized是很合適的。原因在于,編譯程序通常會盡可能的進行優化synchronize,另外可讀性非常好,synchronized它是通過悲觀鎖實現的。
?
2.ReentrantLock:
在資源競爭不激烈的情形下,性能稍微比synchronized差點點。但是當同步非常激烈的時候,synchronized的性能一下子能下降好幾十倍,而ReentrantLock確還能維持常態。
高并發量情況下使用ReentrantLock。
?
3.Atomic:
和上面的類似,不激烈情況下,性能比synchronized略遜,而激烈的時候,也能維持常態。激烈的時候,Atomic的性能會優于ReentrantLock一倍左右。但是其有一個缺點,就是只能同步一個值,一段代碼中只能出現一個Atomic的變量,多于一個同步無效。因為他不能在多個Atomic之間同步,是基于cas操作來實現的,它是通過樂觀鎖來實現的。
?
參考地址:https://youzhixueyuan.com/4-kinds-of-java-thread-locks.html? 然后自己再對比比較和精簡分析
?
?
4?synchronized與Lock的區別
1).首先synchronized是java內置關鍵字,是在在jvm層面,Lock是一個接口,最后是由CPU來發送lock和unlock指令,這個和volatile底層原理實現類似。
2).synchronized無法判斷是否獲取鎖的狀態,Lock可以判斷是否獲取到鎖;
3 ) .synchronized會自動釋放鎖(a?線程執行完同步代碼會釋放鎖 ;b 線程執行過程中發生異常會釋放鎖),Lock需在finally中手工釋放鎖(unlock()方法釋放鎖),否則容易造成線程死鎖;
4) .用synchronized關鍵字的兩個線程1和線程2,如果當前線程1獲得鎖,線程2線程等待。如果線程1阻塞,線程2則會一直等待下去,而Lock鎖就不一定會等待下去,如果嘗試獲取不到鎖,線程可以不用一直等待就結束了;
5) .synchronized的鎖可重入、不可中斷、非公平,而Lock鎖可重入、可判斷、可公平(兩者皆可)
6) .Lock鎖適合大量同步的代碼的同步問題,synchronized鎖適合代碼少量的同步問題。