可重入锁和不可重入锁
轉自https://www.cnblogs.com/dj3839/p/6580765.html
鎖的簡單應用
用lock來保證原子性(this.count++這段代碼稱為臨界區)
什么是原子性,就是不可分,從頭執行到尾,不能被其他線程同時執行。
可通過CAS來實現原子操作
CAS(Compare and Swap):
CAS操作需要輸入兩個數值,一個舊值(期望操作前的值)和一個新值,在操作期間先比較下舊值有沒有發生變化,如果沒有發生變化,才交換成新值,發生了變化則不交換。
CAS主要通過compareAndSwapXXX()方法來實現,而這個方法的實現需要涉及底層的unsafe類
unsafe類:java不能直接訪問操作系統底層,而是通過本地方法來訪問。Unsafe類提供了硬件級別的原子操作
這里有個介紹原子操作的博客
https://my.oschina.net/xinxingegeya/blog/499223
還有對unsafe類詳解的博客
http://www.cnblogs.com/mickole/articles/3757278.html
?
1 public class Counter{2 private Lock lock = new Lock();3 private int count = 0;4 public int inc(){5 lock.lock();6 this.count++;7 lock.unlock();8 return count;9 } 10 }不可重入鎖
先來設計一種鎖
1 public class Lock{2 private boolean isLocked = false;3 public synchronized void lock() throws InterruptedException{4 while(isLocked){ 5 wait();6 }7 isLocked = true;8 }9 public synchronized void unlock(){ 10 isLocked = false; 11 notify(); 12 } 13 }這其實是個不可重入鎖,舉個例子
1 public class Count{2 Lock lock = new Lock();3 public void print(){4 lock.lock();5 doAdd();6 lock.unlock();7 }8 public void doAdd(){9 lock.lock(); 10 //do something 11 lock.unlock(); 12 } 13 }當調用print()方法時,獲得了鎖,這時就無法再調用doAdd()方法,這時必須先釋放鎖才能調用,所以稱這種鎖為不可重入鎖,也叫自旋鎖。
可重入鎖
設計如下:
1 public class Lock{2 boolean isLocked = false;3 Thread lockedBy = null;4 int lockedCount = 0;5 public synchronized void lock()6 throws InterruptedException{7 Thread thread = Thread.currentThread();8 while(isLocked && lockedBy != thread){9 wait(); 10 } 11 isLocked = true; 12 lockedCount++; 13 lockedBy = thread; 14 } 15 public synchronized void unlock(){ 16 if(Thread.currentThread() == this.lockedBy){ 17 lockedCount--; 18 if(lockedCount == 0){ 19 isLocked = false; 20 notify(); 21 } 22 } 23 } 24 }相對來說,可重入就意味著:線程可以進入任何一個它已經擁有的鎖所同步著的代碼塊。
第一個線程執行print()方法,得到了鎖,使lockedBy等于當前線程,也就是說,執行的這個方法的線程獲得了這個鎖,執行add()方法時,同樣要先獲得鎖,因不滿足while循環的條件,也就是不等待,繼續進行,將此時的lockedCount變量,也就是當前獲得鎖的數量加一,當釋放了所有的鎖,才執行notify()。如果在執行這個方法時,有第二個線程想要執行這個方法,因為lockedBy不等于第二個線程,導致這個線程進入了循環,也就是等待,不斷執行wait()方法。只有當第一個線程釋放了所有的鎖,執行了notify()方法,第二個線程才得以跳出循環,繼續執行。
這就是可重入鎖的特點。
java中常用的可重入鎖
synchronized
java.util.concurrent.locks.ReentrantLock
ps:順便記錄下java中實現原子操作的類(記錄至http://blog.csdn.net/huzhigenlaohu/article/details/51646455)
- AtomicIntegerFieldUpdater:原子更新整型的字段的更新器
- AtomicLongFieldUpdater:原子更新長整型字段的更新器
- AtomicStampedReference:原子更新帶有版本號的引用類型。該類將整型數值與引用關聯起來,可用于原子的更新數據和數據的版本號,可以解決使用CAS進行原子更新時可能出現的ABA問題。
- AtomicReference :原子更新引用類型
- AtomicReferenceFieldUpdater :原子更新引用類型里的字段
- AtomicMarkableReference:原子更新帶有標記位的引用類型。可以原子更新一個布爾類型的標記位和應用類型
- AtomicIntegerArray :原子更新整型數組里的元素
- AtomicLongArray :原子更新長整型數組里的元素
- AtomicReferenceArray : 原子更新引用類型數組的元素
- AtomicBooleanArray :原子更新布爾類型數組的元素
- AtomicBoolean :原子更新布爾類型
- AtomicInteger: 原子更新整型
- AtomicLong: 原子更新長整型
?
轉載于:https://www.cnblogs.com/ffaiss/p/11132984.html
總結
以上是生活随笔為你收集整理的可重入锁和不可重入锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 主管问我:你以为单元测试,只是测试吗?
- 下一篇: 求你了,别再随便打日志了,教你动态修改日