并發(fā)編程:Atomic類與悲觀鎖和樂觀鎖
一、悲觀鎖與樂觀鎖
對于悲觀鎖,認為數(shù)據(jù)發(fā)生并發(fā)沖突的概率很大,讀操作之前就上鎖。synchronized關鍵字,后面 要講的ReentrantLock都是悲觀鎖的典型。
對于樂觀鎖,認為數(shù)據(jù)發(fā)生并發(fā)沖突的概率比較小,讀操作之前不上鎖。等到寫操作的時候,再判 斷數(shù)據(jù)在此期間是否被其他線程修改了。如果被其他線程修改了,就把數(shù)據(jù)重新讀出來,重復該過程; 如果沒有被修改,就寫回去。判斷數(shù)據(jù)是否被修改,同時寫回新值,這兩個操作要合成一個原子操作, 也就是CAS ( Compare And Set )。
AtomicInteger的實現(xiàn)就是典型的樂觀鎖。
AtomicInteger的實現(xiàn)就用的是“自旋”策略,如果拿不到鎖,就會一直重試。
二、ABA問題與解決辦法
到目前為止,CAS都是基于“值”來做比較的。但如果另外一個線程把變量的值從A改為B,再從B改回 到A,那么盡管修改過兩次,可是在當前線程做CAS操作的時候,卻會因為值沒變而認為數(shù)據(jù)沒有被其他 線程修改過,這就是所謂的ABA問題。
舉例來說: 小張欠小李100塊,約定今天還,給打到網(wǎng)銀。 小李家的網(wǎng)銀余額是0,打過來之后應該是100塊。 小張今天還錢這個事小李知道,小李還告訴了自己媳婦。 小張還錢,小李媳婦看到了,就取出來花掉了。 小李恰好在他媳婦取出之后檢查賬戶,一看余額還是0。 然后找小張,要賬。
這其中,小李家的賬戶余額從0到100,再從100到0,小李一開始檢查是0,第二次檢查還是0,就 認為小張沒還錢。 實際上小李媳婦花掉了。 ABA問題。 其實小李可以查看賬戶的收支記錄。
要解決 ABA 問題,不僅要比較“值”,還要比較“版本號”,而這正是 AtomicStampedReference做的事情。