在多線程編程中,鎖是經常使用地控制併發的機制,對於臨界區的資源,須要保證線程之間互斥地訪問。java
可重入鎖,也叫作遞歸鎖,指的是屢次對同一個鎖進行加鎖操做,都不會阻塞線程。實現思路:記錄當前鎖正在被哪一個線程使用,採用計數來統計lock和unlock的調用次數。正常狀況下,lock和unlock的調用次數應該相等,若是不相等就會死鎖。面試
public class Test implements Runnable { ReentrantLock lock = new ReentrantLock(); //定義一個可重入鎖 public void get() { lock.lock(); //第一次調用lock() System.out.println(Thread.currentThread().getId()); set(); lock.unlock(); } public void set() { lock.lock(); //第二次調用lock(),並且會成功,說明lock是可重入鎖 System.out.println(Thread.currentThread().getId()); lock.unlock(); } @Override public void run() { get(); } public static void main(String[] args) { Test ss = new Test(); new Thread(ss).start(); new Thread(ss).start(); new Thread(ss).start(); } }
首先,看看初級的自旋鎖實現方式:編程
public class SpinLock { private AtomicReference<Thread> owner =new AtomicReference<>(); public void lock(){ Thread current = Thread.currentThread(); while(!owner.compareAndSet(null, current)){ } } public void unlock (){ Thread current = Thread.currentThread(); owner.compareAndSet(current, null); } }
實現思路:經過CAS(CompareAndSet)原子操做來更新變量。若是CAS返回true,表示得到了鎖;不然,須要經過while循環檢查,直到得到鎖爲止,這也是爲何叫作自旋鎖的緣由,須要不停的嘗試獲取鎖。多線程
public class SpinLock { private AtomicReference<Thread> owner =new AtomicReference<>(); private int count =0; public void lock(){ Thread current = Thread.currentThread(); if(current==owner.get()) { count++; return ; } while(!owner.compareAndSet(null, current)){ } } public void unlock (){ Thread current = Thread.currentThread(); if(current==owner.get()){ if(count!=0){ count--; }else{ owner.compareAndSet(current, null); } } } }