Java中的鎖

一、悲觀鎖(排它鎖)

 總是假設最壞的情況,每次取數據時都認爲其他線程會修改,所以都會加鎖(讀鎖、寫鎖、行鎖等),當其他線程想要訪問數據時,都需要阻塞掛起。可以依靠數據庫實現,如行鎖、讀鎖和寫鎖等,都是在操作之前加鎖,在Java中,synchronized的思想也是悲觀鎖。

select * from book_info where id =#{id} for update

二、樂觀鎖

 總是認爲不會產生併發問題,每次去取數據的時候總認爲不會有其他線程對數據進行修改,因此不會上鎖,但是在更新時會判斷其他線程在這之前有沒有對數據進行修改,一般會使用版本號機制或CAS操作實現。

 version方式:一般是在數據表中加上一個數據版本號version字段,表示數據被修改的次數,當數據被修改時,version值會加一。當線程A要更新數據值時,在讀取數據的同時也會讀取version值,在提交更新時,若剛纔讀取到的version值爲當前數據庫中的version值相等時才更新,否則重試更新操作,直到更新成功。

核心SQL代碼:

update table set state=1, version=version+1 where id=#{id} and version=#{version};  
if(影響行數>0){
    update table2 set money =money+1 where id=#{id}
}

 

 CAS操作方式:即compare and swap 或者 compare and set,涉及到三個操作數,數據所在的內存值,預期值,新值。當需要更新時,判斷當前內存值與之前取到的值是否相等,若相等,則用新值更新,若失敗則重試,一般情況下是一個自旋操作,即不斷的重試。

三、重入鎖

常見的synchronized和java.util.concurrent.locks.ReentrantLock都是可重入鎖

public class Test implements Runnable {
	public  synchronized void get() {
		System.out.println("name:" + Thread.currentThread().getName() + " get();");
		set();//可傳遞
	}

	public synchronized  void set() {
		System.out.println("name:" + Thread.currentThread().getName() + " set();");
	}

	@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();
		new Thread(ss).start();
	}
}

四、讀寫鎖

       相比Java中的鎖(Locks in Java)裏Lock實現,讀寫鎖更復雜一些。假設你的程序中涉及到對一些共享資源的讀和寫操作,且寫操作沒有讀操作那麼頻繁。在沒有寫操作的時候,兩個線程同時讀一個資源沒有任何問題,所以應該允許多個線程能在同時讀取共享資源。但是如果有一個線程想去寫這些共享資源,就不應該再有其它線程對該資源進行讀或寫(譯者注:也就是說:讀-讀能共存,讀-寫不能共存,寫-寫不能共存)。這就需要一個讀/寫鎖來解決這個問題。Java5在java.util.concurrent包中已經包含了讀寫鎖。儘管如此,我們還是應該瞭解其實現背後的原理。

public class Cache {
	static Map<String, Object> map = new HashMap<String, Object>();
	static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
	static Lock r = rwl.readLock();
	static Lock w = rwl.writeLock();

	// 獲取一個key對應的value
	public static final Object get(String key) {
		r.lock();
		try {
			System.out.println("正在做讀的操作,key:" + key + " 開始");
			Thread.sleep(100);
			Object object = map.get(key);
			System.out.println("正在做讀的操作,key:" + key + " 結束");
			System.out.println();
			return object;
		} catch (InterruptedException e) {

		} finally {
			r.unlock();
		}
		return key;
	}

	// 設置key對應的value,並返回舊有的value
	public static final Object put(String key, Object value) {
		w.lock();
		try {

			System.out.println("正在做寫的操作,key:" + key + ",value:" + value + "開始.");
			Thread.sleep(100);
			Object object = map.put(key, value);
			System.out.println("正在做寫的操作,key:" + key + ",value:" + value + "結束.");
			System.out.println();
			return object;
		} catch (InterruptedException e) {

		} finally {
			w.unlock();
		}
		return value;
	}
}

五、CAS無鎖機制(自旋鎖)

      原理類似於樂觀鎖,

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章