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