Java中的鎖系列1

整篇文章郊霎,我想由淺到深開始寫沼头。剛開始可能會(huì)有一些比較基礎(chǔ)的內(nèi)容。

一、通過一個(gè)典型的并發(fā)問題进倍,了解鎖到底有什么用

開10個(gè)線程土至,對(duì)count變量進(jìn)行++操作,每個(gè)線程執(zhí)行50次++操作猾昆。


10個(gè)線程陶因,每個(gè)線程加50次,理論上垂蜗,應(yīng)該是500;

但是烘苹,讓我們看下實(shí)際的運(yùn)行結(jié)果螟加。

第一次運(yùn)行結(jié)果:


第二次運(yùn)行結(jié)果:


不是500也就算了然爆,每次運(yùn)行的結(jié)果還不一樣曾雕。很顯然剖张,并發(fā)了搔弄。然后顾犹,我們加上synchronized關(guān)鍵字試試炫刷。


結(jié)果如下:


執(zhí)行結(jié)果正確了绍申。但是极阅,我們也發(fā)現(xiàn)增加synchronized后书在,比增加之前執(zhí)行時(shí)間長(zhǎng)了很多拆又。

二栈源、鎖消除和鎖粗化

不難發(fā)現(xiàn) 甚垦, 是因?yàn)槲覀儗?duì)Thread.currentThread().sleep(100);也加了鎖涣雕,導(dǎo)致運(yùn)行變慢迄埃。

然后我們將synchronized的位置改一下侄非。


運(yùn)行結(jié)果如下:


運(yùn)行結(jié)果正確,但是運(yùn)行時(shí)間快了很多福澡。所以革砸,寫代碼的時(shí)候业岁,一定要注意笔时,不該鎖的代碼,不要鎖扒怖。我們通常也把這種原則叫做鎖消除业稼。

但是俯邓!

如果要是我們頻繁的lock和unlock稽鞭,同樣會(huì)導(dǎo)致大量的開銷朦蕴。這個(gè)時(shí)候,我們需要將多個(gè)連續(xù)的鎖擴(kuò)展成一個(gè)范圍更大的鎖赴恨。這個(gè)叫做鎖粗化嘱支。

有的同學(xué)可能會(huì)說了,我粗也不好扔枫,細(xì)也不好倚舀,你想讓我一粗一細(xì)一粗一細(xì)么!

好吧痕貌,這個(gè)就看自己怎么去衡量了…

三舵稠、ReentrantLock類

Java里除了synchronized關(guān)鍵字外室琢,還有很多其他的方式也可以避免并發(fā)問題盈滴。

比如典型的ReentrantLock巢钓,又叫做可重入鎖竿报。

ReentrantLock是繼承自Lock接口。


除了ReentrantLock外芽世,還有ReentrantReadWriteLock


我們可以發(fā)現(xiàn),ReentrantReadWriteLock并沒有直接實(shí)現(xiàn)Lock接口旺矾。

但是夺克,ReentrantReadWriteLock有兩個(gè)方法柬帕,可以獲取ReadLock和WriteLock陷寝,而ReadLock和WriteLock實(shí)現(xiàn)了Lock接口凤跑。ReentrantReadWriteLock的具體使用和實(shí)現(xiàn)我們將在后面的文章中研究。

本文里叛复,我們先了解下ReentrantLock饶火。

首先鹏控, 我們來創(chuàng)建一個(gè)可重入鎖ReentrantLock,先lock肤寝,然后在finally里unlock当辐。


我們來看下執(zhí)行效果:


什么鬼?明明鎖起來了鲤看,怎么結(jié)果不是500缘揪!

檢查下代碼, 發(fā)現(xiàn)ReentrantLock reentrantLock = new ReentrantLock();這行代碼居然寫在run()方法里面。每次執(zhí)行都會(huì)創(chuàng)建一把新的鎖,當(dāng)然沒用......。那應(yīng)該怎么做呢?

肯定是當(dāng)成成員變量抖韩。


改好之后,再看下效果:


所以庞呕,一定記得要保證:需要同步的代碼塊拿到的是同一把鎖。用吐槽大會(huì)池子的話說:知識(shí)點(diǎn)啊有木有蔚鸥。

四乾巧、什么是可重入鎖社裆?怎么證明synchronized和ReentrantLock都是可重入的榄攀?

前面一直在說ReentrantLock贞瞒,字面翻譯過來掰盘,也就是可重入鎖叨橱,但是一直不明白可重入鎖到底是個(gè)什么鬼?

其實(shí),可重入鎖是一個(gè)概念征椒,并不就僅僅指ReentrantLock,雖然它翻譯過來就是這個(gè)意思瓢省。

可重入鎖辩块,也叫做遞歸鎖,指的是同一線程外層函數(shù)獲得鎖之后 四啰,內(nèi)層遞歸函數(shù)仍然有獲取該鎖的代碼欧瘪,但不受影響佛掖。

通俗點(diǎn)說就是在同一個(gè)線程里調(diào)lock()之后拴魄,哪怕不釋放跛溉,然后再調(diào)一次lock()方法关贵,又可以拿到鎖√考簦可重入鎖主要是為了解決遞歸調(diào)用產(chǎn)生的死鎖問題练链。其實(shí)synchronized也是可重入鎖的一種,因?yàn)閷懥藄ynchronized關(guān)鍵字之后奴拦,遞歸調(diào)用可以正常執(zhí)行兑宇。

為了加深理解,我們自己寫一個(gè)不可重入鎖粱坤,來對(duì)比一下可重入鎖隶糕。

我們自己寫的鎖名字叫MyLock,一樣也繼承Lock接口站玄。


然后我們用MyLock來鎖一下試試:


執(zhí)行結(jié)果如下:


結(jié)果正確枚驻!說明我們實(shí)現(xiàn)了鎖的基本功能。

然后我們來實(shí)驗(yàn)一下需要可重入的場(chǎng)景試試株旷。

我們?cè)趓un方法里再登,執(zhí)行兩次count++操作,對(duì)每個(gè)count++執(zhí)行一次加鎖操作晾剖,但是不解鎖锉矢。

代碼如下:


執(zhí)行結(jié)果如下:


可以看出,用我們自己寫的MyLock鎖齿尽,執(zhí)行了一次沽损,程序就死鎖了。

然后我們把lock換成ReentrantLock再來一次循头。

private static?Lock?lock?=?new?ReentrantLock();

再次執(zhí)行绵估,結(jié)果如下:


跟預(yù)期結(jié)果一樣。

然后我們?cè)俑某蒘ynchronized試試卡骂。


結(jié)果同上国裳。

通過這個(gè)實(shí)驗(yàn),我們可以證明全跨,ReentrantLock和synchronized確實(shí)是可重入鎖缝左。

五、synchronized和ReentrantLock的比較

那么問題來了,既然synchronized和ReentrantLock都是可重入鎖渺杉,synchronized那么方便蛇数,還需要ReentrantLock干啥?難道蛋疼少办?

我們可以看下ReentrantLock實(shí)現(xiàn)lock的方式。


然后Sync是繼承自傳說中的AbstractQueuedSynchronizer(AQS)诵原。


另外在ReentrantLock內(nèi)部還定義了另外兩個(gè)類英妓,分別是FairSync和NonFairSync,這兩個(gè)類就是分別對(duì)應(yīng)的鎖公平分配和不公平分配的兩個(gè)實(shí)現(xiàn)绍赛,它們都繼承自Sync(類圖已經(jīng)清晰的描述出來了繼承結(jié)構(gòu))蔓纠。有關(guān)鎖的分配和釋放邏輯都是封裝在了AQS里面。

而Synchronized實(shí)現(xiàn)的同步和上面提到的AQS的方式是不同的吗蚌,AQS實(shí)現(xiàn)了一套自己的算法來實(shí)現(xiàn)共享資源的合理控制(具體算法實(shí)現(xiàn)腿倚,下文分析),而Synchronized實(shí)現(xiàn)的同步控制是基于java內(nèi)部的對(duì)象鎖的蚯妇。

那什么是java內(nèi)部的對(duì)象鎖呢敷燎?

Java內(nèi)部對(duì)象鎖:JVM中每個(gè)對(duì)象和類實(shí)際上都與一把鎖與之相關(guān)聯(lián),對(duì)于對(duì)象來說箩言,監(jiān)視的是這個(gè)對(duì)象變量硬贯,對(duì)于類來說,監(jiān)視的是類變量陨收。當(dāng)虛擬機(jī)裝載類時(shí)饭豹,會(huì)創(chuàng)建一個(gè)Class類的實(shí)例,鎖住的實(shí)際上是這個(gè)類對(duì)應(yīng)的Class累的實(shí)例务漩。對(duì)象鎖是可重入的拄衰,也就是說一個(gè)對(duì)象或者類上的鎖是可以累加的。

然后網(wǎng)上也有一些ReentrantLock和synchronized的性能比較饵骨。

http://blog.csdn.net/lantian0802/article/details/8948696

各種數(shù)據(jù)都顯示翘悉,ReentrantLock無論哪方面都比synchronized好。而且支持更多的特性居触,比如時(shí)間鎖等候镐确、可中斷鎖等候、無塊結(jié)構(gòu)鎖饼煞、多個(gè)條件變量或者鎖投票源葫。

但是!是的砖瞧,我們來但是了息堂!

很多大神還是建議能用synchronized開發(fā)的時(shí)候,盡量別用ReentrantLock,除非能證明synchronized已經(jīng)不適合所在場(chǎng)景荣堰。因?yàn)榇参矗蠖鄶?shù)synchronized塊幾乎從來沒有出現(xiàn)過爭(zhēng)用,而ReentrantLock比synchronized優(yōu)秀是體現(xiàn)在出現(xiàn)高爭(zhēng)用的場(chǎng)景振坚。但是一旦忘記寫unlock了薇搁,那就是死鎖!


下一篇渡八,我們將具體講解java內(nèi)部的對(duì)象鎖啃洋,包括偏向鎖、輕量級(jí)鎖屎鳍、重量級(jí)鎖和自旋鎖宏娄。

Java中的鎖系列2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市逮壁,隨后出現(xiàn)的幾起案子孵坚,更是在濱河造成了極大的恐慌,老刑警劉巖窥淆,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卖宠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡忧饭,警方通過查閱死者的電腦和手機(jī)逗堵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來眷昆,“玉大人蜒秤,你說我怎么就攤上這事⊙钦” “怎么了作媚?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)帅刊。 經(jīng)常有香客問我纸泡,道長(zhǎng),這世上最難降的妖魔是什么赖瞒? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任女揭,我火速辦了婚禮,結(jié)果婚禮上栏饮,老公的妹妹穿的比我還像新娘吧兔。我一直安慰自己,他們只是感情好袍嬉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布境蔼。 她就那樣靜靜地躺著灶平,像睡著了一般。 火紅的嫁衣襯著肌膚如雪箍土。 梳的紋絲不亂的頭發(fā)上逢享,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音吴藻,去河邊找鬼瞒爬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛沟堡,可吹牛的內(nèi)容都是我干的侧但。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼弦叶,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼俊犯!你這毒婦竟也來了妇多?” 一聲冷哼從身側(cè)響起伤哺,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎者祖,沒想到半個(gè)月后立莉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡七问,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年蜓耻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片械巡。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡刹淌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出讥耗,到底是詐尸還是另有隱情有勾,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布古程,位于F島的核電站蔼卡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏挣磨。R本人自食惡果不足惜雇逞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望茁裙。 院中可真熱鬧塘砸,春花似錦、人聲如沸晤锥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至眉踱,卻和暖如春挤忙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背谈喳。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來泰國打工册烈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人婿禽。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓赏僧,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親扭倾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子淀零,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 摘要: 我們已經(jīng)知道,synchronized 是Java的關(guān)鍵字膛壹,是Java的內(nèi)置特性驾中,在JVM層面實(shí)現(xiàn)了對(duì)臨界...
    kingZXY2009閱讀 1,830評(píng)論 0 20
  • 作者: 一字馬胡 轉(zhuǎn)載標(biāo)志 【2017-11-03】 更新日志 前言 在java中,鎖是實(shí)現(xiàn)并發(fā)的關(guān)鍵組件模聋,多個(gè)...
    一字馬胡閱讀 44,151評(píng)論 1 32
  • ----------------------------------------業(yè)精于勤荒于嬉肩民,形成思?xì)в陔S---...
    郭之源閱讀 2,097評(píng)論 0 22
  • Java8張圖 11、字符串不變性 12链方、equals()方法持痰、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,704評(píng)論 0 11
  • 佛說:一切有為法祟蚀,如夢(mèng)幻泡影工窍,如露亦如電,應(yīng)作如是觀前酿。一場(chǎng)夢(mèng)境一場(chǎng)空患雏,有多少人能夠看得透夢(mèng)境,有多少人能夠耐得過虛...
    三修夢(mèng)閱讀 1,086評(píng)論 0 0