概述
多個線程對同一片存儲空間進(jìn)行訪問,這時(shí)存儲空間里面的數(shù)據(jù)叫做共享數(shù)據(jù)先馆。線程并發(fā)進(jìn)行寫操作時(shí)发框,共享數(shù)據(jù)就可能產(chǎn)生安全性問題,解決這個問題除了我們前面介紹的一些鎖類外煤墙,jdk也提供了一個關(guān)鍵字synchronized保證共享數(shù)據(jù)的原子性梅惯。
用法
例子依然可以在github中下載
- 修飾靜態(tài)方法:類級別同步
- 修飾成員方法:對象級別的同步
- 方法塊中使用:對給定對象加鎖宪拥,同步代碼塊
原理
- java 程序?qū)蛹墸簊ynchronized(o)
- 字節(jié)碼層級:monitorenter moniterexit (字節(jié)碼文件中可以看到)
- jvm最底層: 使用lock comxchg .....指令 (保證原子性)
synchronized優(yōu)化
synchronized在jdk1.6之前的版本中,因?yàn)槭侵亓考夋i(需要內(nèi)核的調(diào)度)铣减,效率上有很大問題她君,所以jdk1.6對synchronized的加鎖過程做了一些優(yōu)化,加鎖有了升級的過程葫哗,不再是上來就加重量級鎖缔刹。
無鎖 -> 偏向鎖 -> 輕量級鎖(自旋鎖)-> 重量級鎖
- 無鎖:JVM啟動的4秒內(nèi),偏向鎖沒有打開劣针,那時(shí)普通對象是無鎖
- 偏向鎖: markword 上記錄當(dāng)前線程指針校镐,下次同一個線程加鎖的時(shí)候,不需要爭用捺典,只需要判斷線程指針是否同一個鸟廓,所以偏向加鎖的第一個線程。hashCode備份在線程棧上襟己。
- 輕量級鎖: 有爭用時(shí)引谜,鎖升級為輕量級鎖,每個線程有自己的LockRecord在自己的線程棧上稀蟋,用CAS去爭用markword的LR的指針煌张,指針指向哪個線程的LR,哪個線程就擁有鎖
- 重量級鎖:當(dāng)jvm覺得沖突比較大退客,CAS自旋浪費(fèi)cpu時(shí)骏融,升級為重量級鎖。
還有一些其他的優(yōu)化萌狂。
- 鎖消除:當(dāng)jvm檢測上下文档玻,發(fā)現(xiàn)不存在多線程競爭時(shí),進(jìn)行鎖消除茫藏。如:方法內(nèi)部使用StringBuffer類(我們知道這里類的方法時(shí)加了synchronized的)
- 鎖粗化:當(dāng)jvm檢測到在一個while等循環(huán)里面使用了synchronized時(shí)误趴,多次進(jìn)行加鎖的判斷和檢查浪費(fèi)時(shí)間,那就直接放大到while外層吧务傲,這就是鎖粗化凉当。如:while循環(huán)中使用StringBuffer類。
和reentrantLock的區(qū)別
- 使用方式不同: synchronized是jvm提供的關(guān)鍵字售葡,ReentrantLock是API層級的使用看杭。
- 是否可以重入: 兩個都可以重入
- 是否可以實(shí)現(xiàn)公平鎖: synchronized只能不公平,ReentrantLock可公平可不公平
- 是否可以進(jìn)行條件等待: synchronized不行挟伙,ReentrantLock可以實(shí)現(xiàn)Condition等待