Java中有各式各樣的鎖,大致可以分為以下幾類
- 公平鎖 / 非公平鎖
- 可重入鎖
- 互斥鎖 / 共享鎖
- 樂觀鎖 / 悲觀鎖
- 分段鎖
- 偏向鎖 / 輕量級鎖 / 重量級鎖
- 自旋鎖
公平鎖 / 非公平鎖
公平鎖是指多個線程按照申請鎖的順序來獲取鎖。 非公平鎖是指多個線程獲取鎖的順序并不是按照申請鎖的順序盟蚣,有可能后申請的線程比先申請的線程優(yōu)先獲取鎖味抖。 對于Java ReentrantLock而言蜗搔,通過構(gòu)造函數(shù)指定該鎖是否是公平鎖厌蔽,默認是非公平鎖。非公平鎖的優(yōu)點在于吞吐量比公平鎖大握爷。 對于Synchronized而言,也是一種非公平鎖严里。
可重入鎖
可重入鎖又叫遞歸鎖新啼, 同一個線程在外層方法獲取鎖時,進入內(nèi)層方法自動獲取鎖不會被阻塞
ReentrantLock和Synchronized都是可重入鎖
以下例子刹碾,如果synchronized不是可重入鎖的話就有可能造成死鎖
synchronized void setA() throws Exception{
Thread.sleep(1000);
setB();
}
synchronized void setB() throws Exception{
Thread.sleep(1000);
}
互斥鎖 / 共享鎖
- 互斥鎖:X鎖燥撞,只能被一個線程持有,寫鎖是互斥鎖
- 共享鎖:S鎖迷帜,可以被多個線程持有物舒,讀鎖是共享鎖
樂觀鎖 / 悲觀鎖
樂觀鎖和悲觀鎖并不是具體指什么類型的鎖,而是對待并發(fā)同步的方式
- 悲觀鎖認為對于同一個數(shù)據(jù)的并發(fā)操作戏锹,一定是會發(fā)生修改的冠胯,哪怕沒有修改,也會認為修改锦针。因此對于同一個數(shù)據(jù)的并發(fā)操作荠察,悲觀鎖采取加鎖的形式。
- 樂觀鎖則認為對于同一個數(shù)據(jù)的并發(fā)操作奈搜,是不會發(fā)生修改的悉盆。在更新數(shù)據(jù)的時候,會采用嘗試更新馋吗,不斷重新的方式更新數(shù)據(jù)舀瓢。
悲觀鎖在Java中是用各種具體的鎖來實現(xiàn)的,樂觀鎖是無鎖耗美,采用CAS算法實現(xiàn)京髓,CAS有3個操作數(shù),內(nèi)存值V商架,舊的預期值A堰怨,要修改的新值B。當且僅當預期值A和內(nèi)存值V相同時蛇摸,將內(nèi)存值V修改為B备图,否則什么都不做。
分段鎖
分段鎖不是一種具體的鎖,而是一種鎖的設計揽涮,通過細化鎖的粒度提高性能
Java7中的ConcurrentHashMap就采用了分段鎖的設計抠藕,當進行put操作時,先通過hashcode找到要插入的分段中蒋困,然后對該分段進行加鎖盾似。當多個線程進行put操作時,只要不是在同一個分段中就能執(zhí)行并行插入
偏向鎖 / 輕量級鎖 / 重量級鎖
- 偏向鎖是指一段同步代碼一直被一個線程所訪問雪标,那么該線程會自動獲取鎖零院。降低獲取鎖的代價。
- 輕量級鎖是指當鎖是偏向鎖的時候村刨,被另一個線程所訪問告抄,偏向鎖就會升級為輕量級鎖,其他線程會通過自旋的形式嘗試獲取鎖嵌牺,不會阻塞打洼,提高性能。
- 重量級鎖是指當鎖為輕量級鎖的時候逆粹,另一個線程雖然是自旋募疮,但自旋不會一直持續(xù)下去,當自旋一定次數(shù)的時候枯饿,還沒有獲取到鎖酝锅,就會進入阻塞,該鎖膨脹為重量級鎖奢方。重量級鎖會讓其他申請的線程進入阻塞搔扁,性能降低。
自旋鎖
嘗試獲取鎖的線程不會阻塞而是采用循環(huán)的方式獲取鎖蟋字,可以減少線程切換的切換但是會消耗CPU