1.互斥同步
synchronized 和 ReentrantLock。
2.非阻塞同步
互斥同步最主要的問(wèn)題就是線程阻塞和喚醒所帶來(lái)的性能問(wèn)題,因此這種同步也稱(chēng)為阻塞同步。
互斥同步屬于一種悲觀的并發(fā)策略,總是認(rèn)為只要不去做正確的同步措施,那就肯定會(huì)出現(xiàn)問(wèn)題。無(wú)論共享數(shù)據(jù)是否真的會(huì)出現(xiàn)競(jìng)爭(zhēng),它都要進(jìn)行加鎖(這里討論的是概念模型,實(shí)際上虛擬機(jī)會(huì)優(yōu)化掉很大一部分不必要的加鎖)、用戶(hù)態(tài)核心態(tài)轉(zhuǎn)換、維護(hù)鎖計(jì)數(shù)器和檢查是否有被阻塞的線程需要喚醒等操作。
CAS
隨著硬件指令集的發(fā)展,我們可以使用基于沖突檢測(cè)的樂(lè)觀并發(fā)策略: 先進(jìn)行操作,如果沒(méi)有其它線程爭(zhēng)用共享數(shù)據(jù),那操作就成功了,否則采取補(bǔ)償措施(不斷地重試,直到成功為止)。這種樂(lè)觀的并發(fā)策略的許多實(shí)現(xiàn)都不需要將線程阻塞,因此這種同步操作稱(chēng)為非阻塞同步。
樂(lè)觀鎖需要操作和沖突檢測(cè)這兩個(gè)步驟具備原子性,這里就不能再使用互斥同步來(lái)保證了,只能靠硬件來(lái)完成。硬件支持的原子性操作最典型的是: 比較并交換(Compare-and-Swap,CAS)。CAS 指令需要有 3 個(gè)操作數(shù),分別是內(nèi)存地址 V、舊的預(yù)期值 A 和新值 B。當(dāng)執(zhí)行操作時(shí),只有當(dāng) V 的值等于 A,才將 V 的值更新為 B。
AtomicInteger
J.U.C 包里面的整數(shù)原子類(lèi) AtomicInteger,其中的 compareAndSet() 和 getAndIncrement() 等方法都使用了 Unsafe 類(lèi)的 CAS 操作。
3.無(wú)同步方案
要保證線程安全,并不是一定就要進(jìn)行同步。如果一個(gè)方法本來(lái)就不涉及共享數(shù)據(jù),那它自然就無(wú)須任何同步措施去保證正確性。
棧封閉
多個(gè)線程訪問(wèn)同一個(gè)方法的局部變量時(shí),不會(huì)出現(xiàn)線程安全問(wèn)題,因?yàn)榫植孔兞看鎯?chǔ)在虛擬機(jī)棧中,屬于線程私有的。
線程本地存儲(chǔ)(Thread Local Storage)
如果一段代碼中所需要的數(shù)據(jù)必須與其他代碼共享,那就看看這些共享數(shù)據(jù)的代碼是否能保證在同一個(gè)線程中執(zhí)行。如果能保證,我們就可以把共享數(shù)據(jù)的可見(jiàn)范圍限制在同一個(gè)線程之內(nèi),這樣,無(wú)須同步也能保證線程之間不出現(xiàn)數(shù)據(jù)爭(zhēng)用的問(wèn)題。