亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

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

DevWiki / 1465人閱讀

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

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

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

private static AtomicInteger i = new AtomicInteger(0);

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

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

好,這是上次的一點小問題我們再這里重復(fù)一下,接下來我們聊一聊具體的鎖。

互斥同步

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

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

ReentrantLock lock = new ReentrantLock();

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

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

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

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

公平策略與非公平策略

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

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

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

非互斥同步

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

鎖優(yōu)化

我們再來談一談鎖優(yōu)化,JVM為我們的代碼或者說其內(nèi)部就做了一些優(yōu)化方式,我們就來簡單的說幾個。

自旋

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

自適應(yīng)自旋

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

鎖消除

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

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

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

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/76670.html

相關(guān)文章

  • 淺談Java鎖的問題

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

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

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

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

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

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

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

    Gilbertat 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<