Java并发编程—锁的基本概念
在學習或者使用Java的過程中進程會遇到各種各樣的鎖的概念:公平鎖、非公平鎖、自旋鎖、可重入鎖、偏向鎖、輕量級鎖、重量級鎖、讀寫鎖、互斥鎖等待。下邊總結了對各種鎖的解釋
1、公平鎖/非公平鎖
公平鎖是指多個線程在等待同一個鎖時按照申請鎖的先后順序來獲取鎖。相反的非公平鎖是指多個線程獲取鎖的順序并不是按照申請鎖的順序,有可能后申請的線程比先申請的線程優先獲取鎖。
- 公平鎖的好處是等待鎖的線程不會餓死,但是整體效率相對低一些;
- 非公平鎖的好處是整體效率相對高一些,但是有些線程可能會餓死或者說很早就在等待鎖,但要等很久才會獲得鎖。
其中的原因是公平鎖是嚴格按照請求所的順序來排隊獲得鎖的,而非公平鎖時可以搶占的,即如果在某個時刻有線程需要獲取鎖,而這個時候剛好鎖可用,那么這個線程會直接搶占,而這時阻塞在等待隊列的線程則不會被喚醒。對于Java?ReentrantLock而言,通過構造函數指定該鎖是否是公平鎖,默認是非公平鎖。例:new ReentrantLock(true)是公平鎖對于Synchronized而言,也是一種非公平鎖。由于其并不像ReentrantLock是通過AQS的來實現線程調度,所以并沒有任何辦法使其變成公平鎖。
2、可重入鎖
也叫遞歸鎖,是指在外層函數獲得鎖之后,內層遞歸函數仍然可以獲取到該鎖。即線程可以進入任何一個它已經擁有鎖的代碼塊。在JAVA環境下 ReentrantLock 和synchronized 都是可重入鎖。可重入鎖最大的作用是避免死鎖。具體區別下文闡述。
3、自旋鎖
在Java中,自旋鎖是指嘗試獲取鎖的線程不會立即阻塞,而是采用循環的方式去嘗試獲取鎖,這樣的好處是減少線程上下文切換的消耗,缺點是循環會消耗CPU。JDK6中已經變為默認開啟自旋鎖,并且引入了自適應的自旋鎖。自適應意味著自旋的時間不在固定了,而是由前一次在同一個鎖上的自旋時間及鎖的擁有者的狀態來決定。自旋是在輕量級鎖中使用的,在重量級鎖中,線程不使用自旋。
4、悲觀鎖和樂觀鎖
樂觀鎖與悲觀鎖不是指具體的什么類型的鎖,而是指看待并發同步的角度
- 樂觀鎖認為對于同一個數據的并發操作,是不會發生修改的。在更新數據的時候,會采用嘗試更新,不斷重新的方式更新數據。樂觀的認為,不加鎖的并發操作是沒有事情的。即假定不會發生并發沖突,只在提交操作時檢測是否違反數據完整性。(使用版本號或者時間戳來配合實現)。在java中就是無鎖編程,常常采用的是CAS算法,典型的例子就是原子類,通過CAS自旋實現原子操作的更新。
- 悲觀鎖認為對于同一個數據的并發操作,一定是會發生修改的,哪怕沒有修改,也會認為修改。因此對于同一個數據的并發操作,悲觀鎖采取加鎖的形式。悲觀的認為,不加鎖的并發操作一定會出問題。即假定會發生并發沖突,屏蔽一切可能違反數據完整性的操作。在java中就是各種鎖編程。
- 從上面的描述我們可以看出,悲觀鎖適合寫操作非常多的場景,樂觀鎖適合讀操作非常多的場景,不加鎖會帶來大量的性能提升。
5、共享鎖和獨占鎖
- 共享鎖:如果事務T對數據A加上共享鎖后,則其他事務只能對A再加共享鎖,不能加排它鎖。獲準共享鎖的事務只能讀數據,不能修改數據。
- 獨占鎖:如果事務T對數據A加上獨占鎖后,則其他事務不能再對A加任何類型的鎖。獲得獨占鎖的事務即能讀數據又能修改數據。如Synchronized
6、互斥鎖和讀寫鎖
??獨占鎖/共享鎖就是一種廣義的說法,互斥鎖/讀寫鎖就是具體的實現。
- ?互斥鎖:就是指一次最多只能有一個線程持有的鎖。在JDK中synchronized和JUC的Lock就是互斥鎖。
- ?讀寫鎖:讀寫鎖是一個資源能夠被多個讀線程訪問,或者被一個寫線程訪問但不能同時存在讀線程。Java當中的讀寫鎖通過ReentrantReadWriteLock實現。ReentrantReadWriteLock運行一個資源可以被多個讀操作訪問,或者一個寫操作訪問,但兩者不能同時進行。
總結
以上是生活随笔為你收集整理的Java并发编程—锁的基本概念的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java并发编程—AQS原理分析
- 下一篇: java美元兑换,(Java实现) 美元