日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java的LockSupport.park()实现分析

發布時間:2023/12/9 java 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java的LockSupport.park()实现分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

LockSupport類是Java6(JSR166-JUC)引入的一個類,提供了基本的線程同步原語。LockSupport實際上是調用了Unsafe類里的函數,歸結到Unsafe里,只有兩個函數:

?park:阻塞當前線程(Block?current?thread),字面理解park,就算占住,停車的時候不就把這個車位給占住了么?起這個名字還是很形象的。

unpark:?使給定的線程停止阻塞(Unblock?the?given?thread?blocked )。

  • public?native?void?unpark(Thread?jthread);??
  • public?native?void?park(boolean?isAbsolute,?long?time);??
  • ?

    isAbsolute參數是指明時間是絕對的,還是相對的。

    僅僅兩個簡單的接口,就為上層提供了強大的同步原語。

    先來解析下兩個函數是做什么的。

    unpark函數為線程提供“許可(permit)”,線程調用park函數則等待“許可”。這個有點像信號量,但是這個“許可”是不能疊加的,“許可”是一次性的。

    比如線程B連續調用了三次unpark函數,當線程A調用park函數就使用掉這個“許可”,如果線程A再次調用park,則進入等待狀態。

    注意,unpark函數可以先于park調用。比如線程B調用unpark函數,給線程A發了一個“許可”,那么當線程A調用park時,它發現已經有“許可”了,那么它會馬上再繼續運行。

    實際上,park函數即使沒有“許可”,有時也會無理由地返回,這點等下再解析。

    park和unpark的靈活之處

    上面已經提到,unpark函數可以先于park調用,這個正是它們的靈活之處。

    一個線程它有可能在別的線程unPark之前,或者之后,或者同時調用了park,那么因為park的特性,它可以不用擔心自己的park的時序問題,否則,如果park必須要在unpark之前,那么給編程帶來很大的麻煩!!

    考慮一下,兩個線程同步,要如何處理?

    在Java5里是用wait/notify/notifyAll來同步的。wait/notify機制有個很蛋疼的地方是,比如線程B要用notify通知線程A,那么線程B要確保線程A已經在wait調用上等待了,否則線程A可能永遠都在等待。編程的時候就會很蛋疼。

    另外,是調用notify,還是notifyAll?

    notify只會喚醒一個線程,如果錯誤地有兩個線程在同一個對象上wait等待,那么又悲劇了。為了安全起見,貌似只能調用notifyAll了。

    park/unpark模型真正解耦了線程之間的同步,線程之間不再需要一個Object或者其它變量來存儲狀態,不再需要關心對方的狀態。

    ?

    HotSpot里park/unpark的實現

    每個java線程都有一個Parker實例,Parker類是這樣定義的:

    ?

    [cpp]?view plaincopy
  • class?Parker?:?public?os::PlatformParker?{??
  • private:??
  • ??volatile?int?_counter?;??
  • ??...??
  • public:??
  • ??void?park(bool?isAbsolute,?jlong?time);??
  • ??void?unpark();??
  • ??...??
  • }??
  • class?PlatformParker?:?public?CHeapObj<mtInternal>?{??
  • ??protected:??
  • ????pthread_mutex_t?_mutex?[1]?;??
  • ????pthread_cond_t??_cond??[1]?;??
  • ????...??
  • }??
  • 可以看到Parker類實際上用Posix的mutex,condition來實現的。

    ?

    在Parker類里的_counter字段,就是用來記錄所謂的“許可”的。

    當調用park時,先嘗試直接能否直接拿到“許可”,即_counter>0時,如果成功,則把_counter設置為0,并返回:

    ?

    [cpp]?view plaincopy
  • void?Parker::park(bool?isAbsolute,?jlong?time)?{??
  • ??//?Ideally?we'd?do?something?useful?while?spinning,?such??
  • ??//?as?calling?unpackTime().??
  • ??
  • ??
  • ??//?Optional?fast-path?check:??
  • ??//?Return?immediately?if?a?permit?is?available.??
  • ??//?We?depend?on?Atomic::xchg()?having?full?barrier?semantics??
  • ??//?since?we?are?doing?a?lock-free?update?to?_counter.??
  • ??if?(Atomic::xchg(0,?&_counter)?>?0)?return;??
  • ?

    ?

    如果不成功,則構造一個ThreadBlockInVM,然后檢查_counter是不是>0,如果是,則把_counter設置為0,unlock mutex并返回:

    ?

    [cpp]?view plaincopy
  • ThreadBlockInVM?tbivm(jt);??
  • if?(_counter?>?0)??{?//?no?wait?needed??
  • ??_counter?=?0;??
  • ??status?=?pthread_mutex_unlock(_mutex);??
  • ?

    否則,再判斷等待的時間,然后再調用pthread_cond_wait函數等待,如果等待返回,則把_counter設置為0,unlock mutex并返回:

    ?

    [cpp]?view plaincopy
  • if?(time?==?0)?{??
  • ??status?=?pthread_cond_wait?(_cond,?_mutex)?;??
  • }??
  • _counter?=?0?;??
  • status?=?pthread_mutex_unlock(_mutex)?;??
  • assert_status(status?==?0,?status,?"invariant")?;??
  • OrderAccess::fence();??
  • 當unpark時,則簡單多了,直接設置_counter為1,再unlock mutext返回。如果_counter之前的值是0,則還要調用pthread_cond_signal喚醒在park中等待的線程:

    ?

    ?

    [cpp]?view plaincopy
  • void?Parker::unpark()?{??
  • ??int?s,?status?;??
  • ??status?=?pthread_mutex_lock(_mutex);??
  • ??assert?(status?==?0,?"invariant")?;??
  • ??s?=?_counter;??
  • ??_counter?=?1;??
  • ??if?(s?<?1)?{??
  • ?????if?(WorkAroundNPTLTimedWaitHang)?{??
  • ????????status?=?pthread_cond_signal?(_cond)?;??
  • ????????assert?(status?==?0,?"invariant")?;??
  • ????????status?=?pthread_mutex_unlock(_mutex);??
  • ????????assert?(status?==?0,?"invariant")?;??
  • ?????}?else?{??
  • ????????status?=?pthread_mutex_unlock(_mutex);??
  • ????????assert?(status?==?0,?"invariant")?;??
  • ????????status?=?pthread_cond_signal?(_cond)?;??
  • ????????assert?(status?==?0,?"invariant")?;??
  • ?????}??
  • ??}?else?{??
  • ????pthread_mutex_unlock(_mutex);??
  • ????assert?(status?==?0,?"invariant")?;??
  • ??}??
  • }??
  • 簡而言之,是用mutex和condition保護了一個_counter的變量,當park時,這個變量置為了0,當unpark時,這個變量置為1。
    值得注意的是在park函數里,調用pthread_cond_wait時,并沒有用while來判斷,所以posix condition里的"Spurious wakeup"一樣會傳遞到上層Java的代碼里。

    ?

    關于"Spurious wakeup",參考上一篇blog:http://blog.csdn.net/hengyunabc/article/details/27969613

    ?

    [cpp]?view plaincopy
  • if?(time?==?0)?{??
  • ??status?=?pthread_cond_wait?(_cond,?_mutex)?;??
  • }??
  • ?

    這也就是為什么Java dos里提到,當下面三種情況下park函數會返回:

    ?

    • Some other thread invokes unpark with the current thread as the target; or
    • Some other thread interrupts the current thread; or
    • The call spuriously (that is, for no reason) returns.

    ?

    相關的實現代碼在:

    http://hg.openjdk.java.net/build-infra/jdk7/hotspot/file/52c4a1ae6adc/src/share/vm/runtime/park.hpp
    http://hg.openjdk.java.net/build-infra/jdk7/hotspot/file/52c4a1ae6adc/src/share/vm/runtime/park.cpp
    http://hg.openjdk.java.net/build-infra/jdk7/hotspot/file/52c4a1ae6adc/src/os/linux/vm/os_linux.hpp
    http://hg.openjdk.java.net/build-infra/jdk7/hotspot/file/52c4a1ae6adc/src/os/linux/vm/os_linux.cpp ?

    其它的一些東東:

    Parker類在分配內存時,使用了一個技巧,重載了new函數來實現了cache line對齊。

    ?

    [cpp]?view plaincopy
  • //?We?use?placement-new?to?force?ParkEvent?instances?to?be??
  • //?aligned?on?256-byte?address?boundaries.??This?ensures?that?the?least??
  • //?significant?byte?of?a?ParkEvent?address?is?always?0.??
  • ???
  • void?*?operator?new?(size_t?sz)?;??
  • Parker里使用了一個無鎖的隊列在分配釋放Parker實例:

    ?

    ?

    [cpp]?view plaincopy
  • volatile?int?Parker::ListLock?=?0?;??
  • Parker?*?volatile?Parker::FreeList?=?NULL?;??
  • ??
  • Parker?*?Parker::Allocate?(JavaThread?*?t)?{??
  • ??guarantee?(t?!=?NULL,?"invariant")?;??
  • ??Parker?*?p?;??
  • ??
  • ??//?Start?by?trying?to?recycle?an?existing?but?unassociated??
  • ??//?Parker?from?the?global?free?list.??
  • ??for?(;;)?{??
  • ????p?=?FreeList?;??
  • ????if?(p??==?NULL)?break?;??
  • ????//?1:?Detach??
  • ????//?Tantamount?to?p?=?Swap?(&FreeList,?NULL)??
  • ????if?(Atomic::cmpxchg_ptr?(NULL,?&FreeList,?p)?!=?p)?{??
  • ???????continue?;??
  • ????}??
  • ??
  • ????//?We've?detached?the?list.??The?list?in-hand?is?now??
  • ????//?local?to?this?thread.???This?thread?can?operate?on?the??
  • ????//?list?without?risk?of?interference?from?other?threads.??
  • ????//?2:?Extract?--?pop?the?1st?element?from?the?list.??
  • ????Parker?*?List?=?p->FreeNext?;??
  • ????if?(List?==?NULL)?break?;??
  • ????for?(;;)?{??
  • ????????//?3:?Try?to?reattach?the?residual?list??
  • ????????guarantee?(List?!=?NULL,?"invariant")?;??
  • ????????Parker?*?Arv?=??(Parker?*)?Atomic::cmpxchg_ptr?(List,?&FreeList,?NULL)?;??
  • ????????if?(Arv?==?NULL)?break?;??
  • ??
  • ????????//?New?nodes?arrived.??Try?to?detach?the?recent?arrivals.??
  • ????????if?(Atomic::cmpxchg_ptr?(NULL,?&FreeList,?Arv)?!=?Arv)?{??
  • ????????????continue?;??
  • ????????}??
  • ????????guarantee?(Arv?!=?NULL,?"invariant")?;??
  • ????????//?4:?Merge?Arv?into?List??
  • ????????Parker?*?Tail?=?List?;??
  • ????????while?(Tail->FreeNext?!=?NULL)?Tail?=?Tail->FreeNext?;??
  • ????????Tail->FreeNext?=?Arv?;??
  • ????}??
  • ????break?;??
  • ??}??
  • ??
  • ??if?(p?!=?NULL)?{??
  • ????guarantee?(p->AssociatedWith?==?NULL,?"invariant")?;??
  • ??}?else?{??
  • ????//?Do?this?the?hard?way?--?materialize?a?new?Parker..??
  • ????//?In?rare?cases?an?allocating?thread?might?detach??
  • ????//?a?long?list?--?installing?null?into?FreeList?--and??
  • ????//?then?stall.??Another?thread?calling?Allocate()?would?see??
  • ????//?FreeList?==?null?and?then?invoke?the?ctor.??In?this?case?we??
  • ????//?end?up?with?more?Parkers?in?circulation?than?we?need,?but??
  • ????//?the?race?is?rare?and?the?outcome?is?benign.??
  • ????//?Ideally,?the?#?of?extant?Parkers?is?equal?to?the??
  • ????//?maximum?#?of?threads?that?existed?at?any?one?time.??
  • ????//?Because?of?the?race?mentioned?above,?segments?of?the??
  • ????//?freelist?can?be?transiently?inaccessible.??At?worst??
  • ????//?we?may?end?up?with?the?#?of?Parkers?in?circulation??
  • ????//?slightly?above?the?ideal.??
  • ????p?=?new?Parker()?;??
  • ??}??
  • ??p->AssociatedWith?=?t?;??????????//?Associate?p?with?t??
  • ??p->FreeNext???????=?NULL?;??
  • ??return?p?;??
  • }??
  • ??
  • ??
  • void?Parker::Release?(Parker?*?p)?{??
  • ??if?(p?==?NULL)?return?;??
  • ??guarantee?(p->AssociatedWith?!=?NULL,?"invariant")?;??
  • ??guarantee?(p->FreeNext?==?NULL??????,?"invariant")?;??
  • ??p->AssociatedWith?=?NULL?;??
  • ??for?(;;)?{??
  • ????//?Push?p?onto?FreeList??
  • ????Parker?*?List?=?FreeList?;??
  • ????p->FreeNext?=?List?;??
  • ????if?(Atomic::cmpxchg_ptr?(p,?&FreeList,?List)?==?List)?break?;??
  • ??}??
  • }??
  • ?

    ?

    總結與扯談

    JUC(Java Util Concurrency)僅用簡單的park, unpark和CAS指令就實現了各種高級同步數據結構,而且效率很高,令人驚嘆。

    轉載于:https://www.cnblogs.com/bendantuohai/p/4653543.html

    總結

    以上是生活随笔為你收集整理的Java的LockSupport.park()实现分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 久久99婷婷 | 亚洲熟妇色自偷自拍另类 | 成人黄色大片在线观看 | 深夜在线观看 | 少妇高潮一区二区三区喷水 | 欧美精品做受xxx性少妇 | 在线成人亚洲 | 亚洲天堂男人av | 成人网久久 | 欧美激情第二页 | 99精品国产一区 | 日日噜噜噜夜夜爽爽狠狠视频97 | 欧美在线资源 | www.欧美一区二区三区 | 成人亚洲一区二区 | 手机看片一区二区 | 免费播放av | 国产一区二区久久久 | 456亚洲视频 | 最近日韩中文字幕中文 | 韩国三级视频在线 | 日本三级视频在线播放 | 美女三级黄色 | 色秀av| 91精彩刺激对白 | 日韩精品视频在线免费观看 | 亚洲乱码国产乱码精品 | 亚洲日本中文字幕在线 | 五月婷婷丁香综合 | 黄色av三级 | 亚洲视频一二三四 | 伊人av影院 | 国产精品视频网址 | 西西444www大胆无视频 | 国产爽爽爽 | 97人人模人人爽人人少妇 | 午夜精品在线 | 男女草逼 | 国产偷人妻精品一区二区在线 | www夜夜操 | www日日日| 日韩成人区| 黄色性网站| 五月婷婷伊人网 | wwwxxxx在线观看 | chinese中国性按摩hd | 91欧美日韩国产 | 在线观看亚洲精品 | 91本色| 午夜综合 | 女人裸体无遮挡 | 日本美女a级片 | 在线观看免费av网站 | 嫩草影院在线视频 | 亚州男人的天堂 | 青娱乐在线播放 | 夜夜夜网站 | 少妇饥渴难耐 | 2019国产精品 | 日韩精品影院 | 国产精品2019 | 久久偷看各类女兵18女厕嘘嘘 | 69亚洲| 国产黄色一级片 | 少妇在线播放 | 少妇一晚三次一区二区三区 | 久久99精品久久久久久琪琪 | 久久精品视频免费播放 | 97午夜| 国产成人短视频在线观看 | 青娱网电信一区电信二区电信三区 | 日韩精品一区二区在线观看 | 欧美日韩少妇 | 日韩视频 中文字幕 | 超碰97成人 | 91亚洲精品乱码久久久久久蜜桃 | 国产色拍| 免费视频二区 | 色蜜桃av | 男同精品 | 99免费在线观看视频 | 欧美性猛交xxxx偷拍洗澡 | 一级特黄毛片 | 一级裸体片| 亚洲天堂美女视频 | 国产成人精品一区二区三区无码熬 | 欧美黄色性视频 | 超碰在线观看免费 | 久久婷婷激情 | www.黄色片网站 | 久久无码专区国产精品s | 国产激情无码一区二区三区 | 字幕网av| 国产精品xxx | 欧美在线一二 | 亚洲天堂视频在线播放 | 台湾佬美性中文网 | 手机av网站 | 成人三级在线视频 |