(本文作者溫少,首發于博客園,轉載請注明)
非阻塞算法的關鍵思想就是CAS,CAS是compare and
set的縮寫,也常被稱為lock-free或者wait-free,通過把compare和set兩個操作原子化,使得不需要使用鎖,但是能夠解決并發
中的資源爭用問題。由于CAS常常是一個回退算法+死循環,所以又被稱為spin-lock。由于CAS沒有使用鎖,線程持續執行,又稱為非阻塞算法
(non-blocking)。術語不統一,但是都差不多表示同一個東西,我都列在這里,方便大家理解。
CAS通常并發性能會更好,原因有二:
1、CAS由硬件提供指令支持
2、整個思路屬于樂觀鎖定,而不同于其他類型的鎖所采用的悲觀鎖定,大多數并發程序,沖突發生時間較少,所以樂觀鎖定更高效。
非
阻塞算法是當前的一個研究熱點,也越來流行。其顯著的優勢在于避免了鎖帶來的問題,而其主要缺點在于與等價的有鎖算法比較而言,非阻塞算法的實現要復雜一
些。在Java中,doug
lea為我們帶來util.concurrent包,CAS在整個并發框架中深入應用,不單提高了效率(atomic),而且提高了接口可用性(例如
CurrentMap的putIfAbsent)。
有人說,CAS這種技術底層框架提供,不需要了解,其實不然,CAS思想可以應用任何地方,包括數據結構、服務接口、數據庫應用等等。我這篇文章要講的內容就是在關系數據庫應用中使用CAS思想。
閑話少說,言歸正傳!
關
系數據庫數據庫提供了"update T set FState = xx where FState =
xx",執行這樣的SQL,會返回一個更新行數,在jdbc或者odbc或者ADO
.NET中都可以獲得更新行數。上面的SQL,如果更新行數>0,則是更新成功,否則是沒有進行任何更新,這是很典型的CAS。可以說,關系數據庫
原生支持CAS。
例如,現在有一個表:
Create Table T_COUNTER (FName VARCHAR, FCOUNT INT)
這個表存儲一些計數器,程序需要對其中的一個計數器進行increment的操作,實現如下:
// incremnt的實現算法在這個方法里
public int getAndIncrement(String name) {
for (;;) {
int expectValue = getCurrentValue((name);
int updateValue = expectValue + 1;
if (updateCounter(name, expectValue, updateValue)) return expectValue;
}
}
public boolean updateCounter(String name, int expectValue, int updateValue) {
String sql = "UPDATE T_COUNTER SET FCOUNT = @updateValue WHERE FName = @name AND FCOUNT = @expectValue";
int updateCount = executeUpdate(sql);
return updateCount > 0;
}
public int getCurrentValue((String name) {
// SELECT FCOUNT FROM T_COUNTER WHERE FNAME = @name
// TODO 執行這段SQL,返回FCOUNT的值
return 0;
}
private int executeUpdate(String sql) {
// TODO 執行SQL,返回更新行數
return 0;
}
這
樣的實現,避免SQL Server中使用locking hints,Oracle、DB2、MySQL中使用select for
update長時間鎖定T_COUNTER表,性能更好,也更通用。要知道使用locking
hints,不同廠商的數據庫的實現是不一樣的,Oracle和Microsoft SQL Server就相差很大。
這樣做的優點:
1、性能更好
2、鎖表時間更短
3、基于標準SQL,不同的關系數據庫通用
4、上述實現并不復雜
(本文作者溫少,首發于博客園,轉載請注明)