面試前必須要知道的【可重入鎖 自旋鎖】


在多線程編程中,鎖是常用地控制並發的機制,對於臨界區的資源,需要保證線程之間互斥地訪問。

1. 可重入鎖

可重入鎖,也叫做遞歸鎖,指的是多次對同一個鎖進行加鎖操作,都不會阻塞線程。實現思路:記錄當前鎖正在被哪個線程使用,采用計數來統計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();
	}
}

2. 自旋鎖

首先,看看初級的自旋鎖實現方式:

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循環檢查,直到獲得鎖為止,這也是為什么叫做自旋鎖的原因,需要不停的嘗試獲取鎖。

2.1 初級版本的問題
  1. 同一線程前后兩次調用lock(),會導致第二次調用lock時進行自旋,產生了死鎖(因為第一次調用lock()之后,還沒有unlock),說明這個鎖不是可重入的。
  2. 如果問題一已經解決,當第一次調用unlock()時,就已經將鎖釋放了。實際上不應釋放鎖。
2.2 解決方案
  1. 針對問題一:在lock函數內,應驗證線程是否為已經獲得鎖的線程
  2. 針對問題二:采用計數進行統計
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);
			}
		}
	}
}

3. 參考資料

  1. Java鎖的種類以及辨析(四):可重入鎖
  2. 面試必問的CAS,你懂了嗎?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM