1. 程式人生 > >併發程式設計之鎖機制

併發程式設計之鎖機制

併發程式設計之鎖機制

本文是作者對於鎖機制的一些思考和探索,主要是為了方便日後翻閱和學習。

鎖的種類:悲觀鎖 樂觀鎖 獨佔鎖 共享鎖 公平鎖 非公平鎖 分散式鎖 自旋鎖

樂觀鎖 Optimistic Locking /Optimistic concurrency control (OCC)

wiki: 樂觀鎖是一種併發控制方法,主要用於關係型資料庫系統和軟體事物記憶體(software transactional memory (STM) )。
樂觀鎖假設併發事物之間互相不會干擾,在事物完成並提交前,樂觀鎖會確認在它讀取資料時沒有其他的事物修改資料,如果有其他的事物修改了資料的話,事物會進行回滾( rolls back)
樂觀鎖用於資料競爭較少的場景,因為可以節省鎖管理的開銷,並且併發的事物不用等待其他佔有了鎖的事物執行,因此具有較高的吞吐量。
樂觀鎖步驟
開始階段:記錄一個時間戳標識一個樂觀鎖
修改階段: 讀取資料庫儲存的資料,並初步更新
檢驗階段: 檢查是否有其他的事物修改了對應的值
提交階段/回滾階段: 如果事物對於值的更改沒有和其他事物衝突,提交併使更改生效。如果有衝突,解決衝突的方法一般是放棄事物的修改,

應用:
對於無狀態的HTTP WEb應用來說,加鎖是無法實現的,因此只能使用內建樂觀鎖。
HTTP的GET方法返回資源時,會放置一個ETag在headers裡面,後續的方法需要通過if-match匹配ETag,由於ETag是基於第一個GET的資源產生的,所以只會匹配第一個GET。
Mysql資料庫可以使用樂觀鎖來實現併發訪問資料庫,實現方法為為表新增一個version版本控制欄位,當讀取資料時將該欄位讀出,更新資料後對比資料庫該欄位,一致則修改,否則回滾事物。
Java的java.util.concurrent.atomic使用CAS(Compare And Set(或Compare And Swap)演算法實現。

悲觀鎖 Pessimistic Lock

整個資料處理過程中,將資料處於鎖定狀態。悲觀鎖的實現,往往依靠資料庫提供的鎖機制(也只有資料庫層提供的鎖機制才能真正保證資料訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系統不會修改資料)。
由於悲觀鎖時獨佔鎖,其他的事物需要等待獲取鎖以及對於所得管理都會造成較大的資源開銷。

獨佔鎖 Exclusive Lock

當用戶給資料加鎖後,除了這個使用者釋放鎖之外,沒有任何人可以操作這個資料。
用法
SELECT ... FOR UPDATE;
在查詢語句後面增加FOR UPDATE,Mysql會對查詢結果中的每行都加排他鎖,當沒有其他執行緒對查詢結果集中的任何一行使用排他鎖時,可以成功申請排他鎖,否則會被阻塞。

共享鎖 Share Lock

共享鎖又稱讀鎖,是讀取操作建立的鎖。其他使用者可以併發讀取資料,但任何事務都不能對資料進行修改(獲取資料上的排他鎖),直到已釋放所有共享鎖。

用法
SELECT ... LOCK IN SHARE MODE;
在查詢語句後面增加LOCK IN SHARE MODE,Mysql會對查詢結果中的每行都加共享鎖,當沒有其他執行緒對查詢結果集中的任何一行使用排他鎖時,可以成功申請共享鎖,否則會被阻塞。其他執行緒也可以讀取使用了共享鎖的表,而且這些執行緒讀取的是同一個版本的資料。

Java中的讀寫鎖就是一種共享鎖。

[1]: Java高效併發之樂觀鎖悲觀鎖、(互斥同步、非互斥同步)