成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

淺談Java中鎖的實(shí)現(xiàn)和優(yōu)化

DevWiki / 1422人閱讀

摘要:這兩種策略的區(qū)別就在于,公平策略會(huì)讓等待時(shí)間長的線程優(yōu)先執(zhí)行,非公平策略則是等待時(shí)間長的線程不一定會(huì)執(zhí)行,存在一個(gè)搶占資源的問題。

之前有一篇文章我們簡單的談到了Java中同步的問題,但是可能在平常的開發(fā)中,有些理論甚至是某些方式是用不到的,但是從程序的角度看,這些理論思想我們可以運(yùn)用到我們的開發(fā)中,比如是不是應(yīng)該一談到同步問題,就應(yīng)該想到用synchronized?,什么時(shí)候應(yīng)該用ReentrantLock?,是不是應(yīng)該考慮用原子類解決某些問題?那我們就來聊一聊我們?nèi)绾斡眠@個(gè)鎖。

上一篇文章中第一個(gè)例子,我們后來通過對(duì)方法加synchronized修改了代碼,在這里還有一種修改方式,我們可以考慮使用原子類,這樣也可以解決這個(gè)問題,我們來看看偽代碼:

private static AtomicInteger i = new AtomicInteger(0);

private static void increse(){
        i.incrementAndGet();
    }

因?yàn)樵谶@個(gè)問題上,不只是有線程的可見性問題,還有一個(gè)就是操作的原子性問題,說到這里,我們應(yīng)該明白,在我們平常的開發(fā)中,有時(shí)候應(yīng)該區(qū)分什么時(shí)候是需要原子操作,什么時(shí)候只需要可見性,那么這樣我們才能夠正確的判斷用某種合理的方式寫出合理的代碼。

好,這是上次的一點(diǎn)小問題我們?cè)龠@里重復(fù)一下,接下來我們聊一聊具體的鎖。

互斥同步

synchronized就是一個(gè)很典型的例子,這種鎖也叫做可重入鎖,就是一個(gè)線程持有一個(gè)相同的鎖對(duì)象,可以進(jìn)行重復(fù)加解鎖,換句話說,持有相同鎖對(duì)象的線程不會(huì)自己把自己鎖住。

還有另外一個(gè)和synchronized很相近的鎖,就是我們上面提到的ReentrantLock,這個(gè)和synchronized一樣,都提供了可重入性,這兩個(gè)鎖的效果是差不多的(在以前的一些比較舊的JDK版本中,并發(fā)數(shù)比較大的情況下,ReentrantLock的性能是要優(yōu)于synchronized的),可能有些小伙伴還沒有用過這種鎖,那這里我們就簡單說一下具體用法:

ReentrantLock lock = new ReentrantLock();

lock.lock();
// code
lock.unlock();

這里從API的層面提供了一個(gè)比較簡單的寫法,同時(shí)也提供了一些比較高級(jí)的特性,像信號(hào)量,線程終止等等,有興趣的小伙伴可以去查閱相關(guān)資料去了解一下,在這里我們不深入探討,但是有一個(gè)地方需要注意一下,就是ReentrantLock提供了兩種競爭策略,一種是公平策略,另一種是非公平策略。

ReentrantLock lock = new ReentrantLock();// 非公平策略

ReentrantLock lock = new ReentrantLock(true);// 公平策略

公平策略與非公平策略

這里我就先舉一個(gè)比較簡單的例子,如果我們?cè)诠旧习?,有時(shí)候我們中午會(huì)帶午飯,然后需要用微波爐來加熱一下,那這里就有個(gè)問題了,在我們?nèi)ゼ訜嵛顼埖臅r(shí)候,如果前面有同事在排隊(duì),當(dāng)然了,我們都是有素質(zhì)的人,出于禮貌,我們也需要排隊(duì),等待前面的同事操作完,后面來的同事當(dāng)然也需要排在我們后面,那這種情況下,我們可以稱之為公平策略。
如果在前面正在熱午飯的同事,他有關(guān)系比較好的同事也來熱午飯,這個(gè)時(shí)候是否可以插隊(duì),如果這位同事插隊(duì)成功了,那么他就可以繼續(xù)熱午飯了,那么我們又得在后面等了,這種情況我們可以稱之為非公平策略。這兩種策略的區(qū)別就在于,公平策略會(huì)讓等待時(shí)間長的線程優(yōu)先執(zhí)行,非公平策略則是等待時(shí)間長的線程不一定會(huì)執(zhí)行,存在一個(gè)搶占資源的問題。如果從源碼的角度來看,那么我們就來簡單的說一下非公平策略的執(zhí)行方式。

非公平策略執(zhí)行方式

一個(gè)線程首先會(huì)試探性的獲取一次鎖,如果獲取到,則將當(dāng)前鎖設(shè)置為該線程獨(dú)占,如果沒有設(shè)置成功,則再次試探性的獲取一次,如果還是沒有成功,則將該線程加入到等待隊(duì)列,后面再次等待獲取,看到這里,可能有一些小伙伴不太明白了,那么非公平是體現(xiàn)在哪里,如果排在你前面的以為同事剛好熱好午飯,然后你在后面玩手機(jī),前面的同事還沒有跟你說,“喂,該你去熱午飯了。”,然后這會(huì)兒又來了一個(gè)其他人插隊(duì),那么作為高素質(zhì)的你,肯定不能和別人計(jì)較了,好了,那就等著吧,非公平策略就體現(xiàn)在這里了。這里實(shí)現(xiàn)的方式很復(fù)雜,可以一點(diǎn)一點(diǎn)去看,其中有用到AQSCAS等這些比較底層的原理,值得一提的是,現(xiàn)在JVM對(duì)synchronized的優(yōu)化已經(jīng)相當(dāng)不錯(cuò),其性能表型已經(jīng)和ReentrantLock不相上下,如果從推薦的角度來說,還是推薦使用synchronized,除非需要使用一些比較高級(jí)的特性。

非互斥同步

接下來我們?cè)賮砹囊涣氖裁词欠腔コ馔?,互斥同步就是指阻塞同步,就是阻塞線程讓其一直等待某個(gè)鎖可用的過程,那么非互斥同步剛和和這個(gè)是對(duì)立的,這里用到了一個(gè)CAS的原理,這個(gè)是操作系統(tǒng)的指令,即compare and swap,比較并交換,說的簡單一點(diǎn),就是如果在內(nèi)存中一個(gè)值為V,然后我們又一個(gè)預(yù)估值A(chǔ),然后還有一個(gè)新值B,如果V和A相同,那么就把V的值替換為B,然后返回V,這里要說一下,無論是否能替換成功,都會(huì)返回V的值,這個(gè)過程稱作CAS。這種就涉及到操作系統(tǒng)級(jí)別了,因?yàn)樵谥暗淖枞街校枞€程然后再將其恢復(fù)獲得鎖的過程,是比較耗費(fèi)性能的,我們知道,Java中的線程是對(duì)操作系統(tǒng)線程的一個(gè)映射,如果我們?cè)谧枞降臅r(shí)候,將一個(gè)線程掛起,然后再恢復(fù),那么這里要經(jīng)歷一個(gè)向核心態(tài)的轉(zhuǎn)換過程,消耗是比較巨大的。因此,在非互斥同步中,通過CAS這種方式,能夠相對(duì)比較好的處理這個(gè)問題,但是有個(gè)問題需要明確一下,就是在Java中,這種處理方式,是通過這個(gè)類來完成的,sun.misc.Unsafe,這個(gè)類只能通過boot class loader來調(diào)用,要么就是通過反射,或者通過某些方法來調(diào)用,比如AtomicInteger類中的incrementAndGet()方法,當(dāng)然,還有很多這種方法,個(gè)人也是對(duì)CAS這種機(jī)制理解的比較片面,還需要更加深層次的研究。到這里,我們不得不說,Doug Lea的編碼能力實(shí)屬上乘,確實(shí)佩服!

鎖優(yōu)化

我們?cè)賮碚勔徽勬i優(yōu)化,JVM為我們的代碼或者說其內(nèi)部就做了一些優(yōu)化方式,我們就來簡單的說幾個(gè)。

自旋

什么是自旋,是的,有些小伙伴也可以這么理解,就是自己旋轉(zhuǎn),當(dāng)然這是開個(gè)玩笑,不過這種方式對(duì)于阻塞線程來說,是有一定的效果,簡單來說,就是如果一個(gè)線程獲得了鎖,然后另一個(gè)線程按照以前的方式只能阻塞等待,那么JVM對(duì)這里做了一個(gè)優(yōu)化,就是讓這種等待的線程去執(zhí)行一個(gè)循環(huán),但是此時(shí)CPU的時(shí)間片是不會(huì)讓出去的,也就是說這里的這個(gè)線程還是占有著一個(gè)處理時(shí)間,如果循環(huán)結(jié)束之后,這個(gè)鎖就能獲取了,那這個(gè)線程就拿到這個(gè)鎖繼續(xù)執(zhí)行,這樣做的一個(gè)目的就在于我們上面說的,線程從掛起到恢復(fù)需要像核心態(tài)的一個(gè)轉(zhuǎn)換,這個(gè)性能的消耗和占用時(shí)間片的消耗比是很大的,但是同時(shí)也有一個(gè)問題就是如果自旋結(jié)束后,還是沒有獲得鎖,那么這段時(shí)間性能的消耗就是浪費(fèi)了,所以也很難權(quán)衡,因此在一些比較舊的JDK版本中,JVM是禁止使用自旋的。

自適應(yīng)自旋

這里就是說如果一個(gè)線程在一次成功的自旋結(jié)束后,并且成功的獲得了鎖然后成功運(yùn)行,那么JVM會(huì)“認(rèn)為”這次自旋是成功的,那么下次如果繼續(xù)有線程發(fā)生自旋,那么JVM能夠判斷出來是否需要讓這個(gè)線程自旋來減少性能的消耗,從這里來看,JVM還是相對(duì)比較“機(jī)智”的。

鎖消除

這個(gè)例子在上一篇文章中曾經(jīng)提到過,對(duì)于字符串的拼接,我們反編譯就能看出來,如果能夠判斷不存在方法逃逸的情況下,那么JVM會(huì)對(duì)這種操作轉(zhuǎn)換為StringBuilderappend操作,可能有的小伙伴會(huì)有疑問,為什么不轉(zhuǎn)換為StringBuffer呢?因?yàn)?b>JVM已經(jīng)能夠正確判斷出沒有方法逃逸,那么如果再用線程安全類來處理也意義不大。

好了,這篇文章就先到這里了,這里只是很簡略的聊了一下在Java中的鎖的相關(guān)知識(shí),更深入的還有待后面繼續(xù)研究。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/76670.html

相關(guān)文章

  • 淺談Java鎖的問題

    摘要:之前我們簡單的討論了一下關(guān)于中的同步還有一些鎖優(yōu)化的問題,今天我們就來簡單的聊一聊關(guān)于中的死鎖問題。這里顯示兩個(gè)線程的狀態(tài)現(xiàn)在是處于阻塞狀態(tài),然后都在等待鎖的獲取,我們?cè)倮^續(xù)往下看。 之前我們簡單的討論了一下關(guān)于Java中的同步還有一些鎖優(yōu)化的問題,今天我們就來簡單的聊一聊關(guān)于Java中的死鎖問題。 這個(gè)問題我們?cè)陂_發(fā)的時(shí)候,或多或少都能遇到,對(duì)業(yè)務(wù)邏輯沒有正確的梳理,又或者是在多線程...

    fox_soyoung 評(píng)論0 收藏0
  • 【推薦】最新200篇:技術(shù)文章整理

    摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語言和等其他語言的對(duì)比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動(dòng)化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯(cuò)過的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語言和Java、python等其他語言的對(duì)比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...

    BicycleWarrior 評(píng)論0 收藏0
  • 【推薦】最新200篇:技術(shù)文章整理

    摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語言和等其他語言的對(duì)比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動(dòng)化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯(cuò)過的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語言和Java、python等其他語言的對(duì)比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...

    tommego 評(píng)論0 收藏0
  • 淺談java中的并發(fā)控制

    摘要:并發(fā)需要解決的問題功能性問題線程同步面臨兩個(gè)問題,想象下有兩個(gè)線程在協(xié)作工作完成某項(xiàng)任務(wù)。鎖可用于規(guī)定一個(gè)臨界區(qū),同一時(shí)間臨界區(qū)內(nèi)僅能由一個(gè)線程訪問。并發(fā)的數(shù)據(jù)結(jié)構(gòu)線程安全的容器,如等。 并發(fā)指在宏觀上的同一時(shí)間內(nèi)同時(shí)執(zhí)行多個(gè)任務(wù)。為了滿足這一需求,現(xiàn)代的操作系統(tǒng)都抽象出 線程 的概念,供上層應(yīng)用使用。 這篇博文不打算詳細(xì)展開分析,而是對(duì)java并發(fā)中的概念和工具做一個(gè)梳理。沿著并發(fā)模...

    Gilbertat 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<