什么是悲觀鎖锈玉、樂觀鎖?在java語言里义起,總有一些名詞看語義跟本不明白是啥玩意兒拉背,也就總有部分面試官拿著這樣的詞來忽悠面試者,以此來找優(yōu)越感默终,其實(shí)理解清楚了椅棺,這些詞也就唬不住人了犁罩。
- synchronized是悲觀鎖,這種線程一旦得到鎖两疚,其他需要鎖的線程就掛起的情況就是悲觀鎖床估。
- CAS操作的就是樂觀鎖,每次不加鎖而是假設(shè)沒有沖突而去完成某項(xiàng)操作诱渤,如果因?yàn)闆_突失敗就重試顷窒,直到成功為止。
那么問題來了源哩,什么是CAS操作鞋吉?
CAS是Compare-and-swap(比較與替換)的簡寫,是一種有名的無鎖算法励烦,在java中谓着,我們主要分析Unsafe類,因?yàn)樗械腃AS操作都是它來實(shí)現(xiàn)的坛掠,而在Unsafe類中這些方法也都是native方法
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
看到上面的解釋是不是索然無味赊锚,查找了很多資料也沒完全弄明白,通過幾次驗(yàn)證后屉栓,終于明白舷蒲,最終可以理解成一個(gè)無阻塞多線程爭搶資源的模型。先上代碼
package com.company.reentrantLock;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Created by wxwall on 2017/6/2.
*/
public class AtomicBooleanTest implements Runnable{
public static AtomicBoolean exits = new AtomicBoolean(true);
public static void main(String[] args) {
AtomicBooleanTest abd = new AtomicBooleanTest();
Thread t1 = new Thread(abd);
Thread t2 = new Thread(abd);
t1.start();
t2.start();
}
@Override
public void run() {
System.out.println("begin run");
System.out.println("real " + exits.get());
if(exits.compareAndSet(true,false)){
System.out.println(Thread.currentThread().getName() + " " + exits.get() );
exits.set(true);
}else{
run();
}
}
}
輸出結(jié)果:
begin run
real true
Thread-1 false
begin run
real true
Thread-0 false
這里無論怎么運(yùn)行友多,Thread-1牲平、Thread-0都會(huì)執(zhí)行if=true條件,而且還不會(huì)產(chǎn)生線程臟讀臟寫域滥,這是如何做到的了纵柿,這就用到了我們的compareAndSet(boolean expect,boolean update)方法,先上圖簡單講解下程序原理启绰,然后再分析compareAndSet作用昂儒。
這個(gè)圖中重最要的是compareAndSet(true,false)方法要拆開成compare(true)方法和Set(false)方法理解,是compare(true)是等于true后委可,就馬上設(shè)置共享內(nèi)存為false渊跋,這個(gè)時(shí)候,其它線程無論怎么走都無法走到只有得到共享內(nèi)存為true時(shí)的程序隔離方法區(qū)着倾。
但是這種得不到狀態(tài)為true時(shí)使用遞歸算法是很耗cpu資源的拾酝,所以一般情況下,都會(huì)有線程sleep屈呕。
總結(jié)
這篇文章并沒有展開講compareAndSet底層調(diào)用的是unsafe.compareAndSwapInt方法微宝,因?yàn)檫@是native方法,很多人都會(huì)展開找源碼虎眨,最后也只找到是調(diào)用CPU方法蟋软,沒講到具體用法镶摘,如果只用compareAndSet(true,false)舉例則更加簡單。
這種無阻塞式的多線程操作數(shù)據(jù)岳守,在大并發(fā)情況下凄敢,是一筆非常可觀的性能提升湿痢,所以涝缝,如果在大并發(fā)或多線程性能要求高的情況下有更加好的技術(shù)選型,可以參考這種底層實(shí)現(xiàn)譬重。