<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 編程世界的那把鎖 原創?2017-05-08?老劉?[碼農翻身](http://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=2665513653&idx=1&sn=e30c18c0c1780fb3ef0cdb858ee5201e&chksm=80d67af6b7a1f3e059466302c2c04c14d097c1a5de01cf986df84d4677299542f12b974dfde3&scene=21##) 1共享變量惹得禍 我們這里是個典型的弱肉強食的世界, 人口多而資源少,為了爭搶有限的資源,大家都在自己能運行的CPU時間片里拼了老命,經常為了一個變量的修改而打的頭破血流。 100納秒以前, 我有幸占據了CPU,從內存中讀取了一個變量x == 100, 我把它加了1, 休息了一會兒后我打算把它寫回內存, 但是驚奇的發現: 內存中的x 已經變成102了。 估計是哪個不著調的線程在我休息的時候也讀取并且修改了x, ? 有不少好心的線程在沖我喊:不要寫回了! 但是寫回內存是我的指令啊, 你不讓我執行,難道讓我退出? ?我只能毫不客氣的把101寫入內存, 把那個不符合我邏輯的值102給覆蓋掉, 這樣我才能執行下一條指令。 你看,單線程的邏輯正確并不表示多線程并發運行時的邏輯也能正確。? 這樣的事情發生的多了,程序總是無法正確運行, 引起了人類的強烈不滿,小道消息說他們在考慮kill掉我們, 換編程語言了。 但是換編程語言有什么用,只要有共享變量,多線程讀寫的時候就是會出現不一致啊。 除非你消除共享變量,讓每個線程只訪問一個函數內的局部變量, 這些局部變量我們每個線程都會有一份, 函數結束以后就會銷毀,所以線程之間就隔離了,就安全了。 消除共享變量談何容易, 人類使用的很多語言例如C++, Java,那些共享變量大多數一個對象的字段, 你想把字段去掉, 只留下函數, 那類也沒有存在的必要了, 就類似于函數式編程了, 一切都是函數。 ?有時候我挺羨慕函數式的世界, 那種無狀態應該是一種非常美妙的感覺吧。 2**爭搶吧,線程** 既然共享變量是無法消除的,那就想想別的辦法吧, 線程元老院的那幫家伙們哼哧了半天,終于公布了一個方案: 加鎖! 任何線程,只要你想操作一個共享變量,對不起, 先去申請一把鎖, 拿到這把鎖才能讀取x的值 , 修改x的值, ?把x寫回內存, 最后釋放鎖,讓別人去玩。 元老院設計的這把鎖非常簡單, 類似于一個boolean 變量, boolean lock = false. ? ? ? 誰能搶先把這個變量改成true, 就意味著獲取了這把鎖。 來吧,哥幾個,快來搶吧 ! 我運行的時候, 就去檢查lock這個變量是否可以設置為true, 如果被別的家伙給搶到了(已經變成true了), 我就在這里無限循環,拼命的搶, 除非我的時間片到了,被迫讓出CPU, 但是我不會阻塞, 還是就緒狀態,等待下一次的調度, 進入CPU繼續搶。 看到某人把它變成false, 我眼疾手快迅速出手, 終于搶到了,趕緊把lock改成true, 這把鎖現在屬于我了, 趕快去干活,干完活要記住把lock 改成false, ?讓別的家伙們去搶。 我想正是由于這種無限循環的特點, 元老院把他命名為“自旋鎖”吧! 列位看官,可能你已經想到了, 假設有兩個線程,都讀到了lock == false, ?都把lock 改成true, 那這個鎖算誰的? 這個問題元老院的大佬們早就考慮到了, 他們和操作系統(我聽說還有硬件)都商量好了, 這個檢測lock是否為false, 以及設置lock 為true 的操作 其實被合并了, 叫做test_and_set(lock), ?操作系統鄭重承諾,這是一個不可分割的原子操作, 在這個test_and_set執行的時候,總線都被鎖住了, 別人不能訪問內存, 即使有多個CPU在執行也不會亂掉。 如果你感興趣,可以看看下面的實現, 否則直接無視跳過: ![](http://mmbiz.qpic.cn/mmbiz_png/KyXfCrME6UJ0BibQ3YBBhwYvbSJ9ZXfAVSIRD9hMaA3YWYbD7ZKBpOYj9tW6ibKnt2YKs6oA9NyoKxRDfiaksmolA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1) 3改進 有了自旋鎖, 至少可以保證程序的正確運行了, 我們大家都玩的不亦樂乎。 有一天我遇到了一個遞歸函數, 我是挺喜歡遞歸的, 因為邏輯簡單, 只要遞歸的層次別太深, 別搞出棧溢出就好。 ? 這個遞歸函數中需要獲得自旋鎖,做點事情, 然后繼續調用自己, 類似于這樣: ![](http://mmbiz.qpic.cn/mmbiz_png/KyXfCrME6UJ0BibQ3YBBhwYvbSJ9ZXfAVOVLkZHu9z50zoFzhiaoWNrDxqa7o9SK59zyGp5hnicBETEp3Hz3UAoqQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1) 我第一次調用doSomething, 獲取了自旋鎖, 然后第二次調用doSomething, 還要獲取自旋鎖, ?可是這個鎖已經在我第一次調用的時候持有了, 現在第二次調用只有無限的等待了!? 這下尷尬了, 我進退不得, 自己把自己搞成了死鎖! 看來這個自旋鎖雖然能實現互斥的訪問, 但是不能重新進入同一個函數(簡稱不可重入)啊! 我趕緊把這個問題向元老院做了匯報, 修改方案很快就下來了: 每次成功的申請鎖以后,要記錄下到底是誰申請的, 還要用一個計數器記錄重入的次數, 下一次持有鎖的家伙再次申請鎖只是給計數器加一而已。 釋放的時候也是一樣, 把計數器減一, 如果等于0了才真正的釋放鎖。 可重入性就這么解決了, 但是這么多線程都在那里拼命的搶也不是辦法, 空耗CPU也是巨大的浪費啊。 于是元老院又發布了新的鎖 ReentrantLock, 這個鎖可以重入,如果你搶不到, 不要無限循環了, 乖乖的到等待隊列里待著去, 等到鎖被別人釋放了再通知你去搶。 (在Java 中最初是synchronzied關鍵字,可以用在一個方法上或者一個代碼塊上, 后來又改進為更加靈活的ReentrantLock) 很快就有線程還抱怨說, 明明是我先發出獲得鎖的申請啊, 為什么隔壁老王卻先拿到了鎖? 這不公平啊,不行,以后得排隊, 先來先得。 ? 好吧, 只好加上一個是否公平的參數。 還有線程說, 我是個急性子,申請鎖的時候只想等待5秒鐘, 5秒之內得不到鎖我就放棄了, 能不能支持? ?那就再加上一個參數:等待時間。 4**發揚光大** 體會到鎖帶來的甜頭以后, 各種各樣樣的需求紛至沓來:? 1\. 有時候需要多個線程都獲得同一把鎖,去做一件事情,那怎么辦呢? 沒關系,信號量(Semaphore)出馬,創建信號量的時候得指定一個整數(例如10), 表明同一時刻最多有10個線程可以獲得鎖:? Semaphore lock= new Semaphore(10); 當然每個線程都需要調用lock.aquire(), lock.release()去申請/釋放鎖。? 2\. ?一個線程要寫共享變量, 可是還有幾個線程要同時讀, 怎么辦? 你寫的時候可以鎖住, 但總不能讀的時候也只允許一個線程吧? ? 只好來一個讀寫鎖了ReadWriteLock, 為了保證可重入性, 元老院體貼的實現了ReentrantReadWriteLock。 ?3\. 一個線程需要等待其他多個線程完工以后才能干活,怎么辦?? CountDownLatch前來救駕, 搞一個計數器,某個線程干完了就把計數器減去1, 如果計數器為0了,那個一直耐心等待的線程就可以開始了。 4\. 還有幾個線程必須互相等待, 就像100米賽跑那樣, 所有人都準備好了才能開閘放水, 不,是起跑, 就那就賞你一個CyclicBarrier吧。 你看到的只是冰山一角, 更多精彩文章,請移步《[碼農翻身文章精華](http://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=2665513504&idx=1&sn=25dd6420e3056101dd3f6fdaedacaa2a&chksm=80d67a63b7a1f37572a5159ff6f53810467c15c8beec94770e8360c45f45036360d77755ee78&scene=21#wechat_redirect)》 有心得想和大家分享? 歡迎投稿 ! 我的聯系方式:微信:liuxinlehan ?QQ: 3340792577 ![](http://mmbiz.qpic.cn/mmbiz/cZV2hRpuAPgyGRhyoqbTupN7lM2NSVJqkaFQzA59F6kiblIQsL175lxIVZbSLrFDFicibxXiaXpXmAGkrGNSib76Ylw/0?tp=webp&wxfrom=5&wx_lazy=1 "銀色金屬分割線") 優秀人才不缺工作機會,只缺適合自己的好機會。但是他們往往沒有精力從海量機會中找到最適合的那個。 100offer 會對平臺上的人才和企業進行嚴格篩選,讓「最好的人才」和「最好的公司」相遇。 掃描下方二維碼,注冊 100offer,談談你對下一份工作的期待。一周內,收到 5-10 個滿足你要求的好機會! ![](http://mmbiz.qpic.cn/mmbiz_jpg/KyXfCrME6UJVvPVtjbSyfHOHM48VU9x11HEUjEiaBSRuSdsjLTVYk7zosmlmoQbe2ibX2VGpHoRqpupA8Waia6GZA/640?tp=webp&wxfrom=5&wx_lazy=1) * * * * * create date:2017-7-15 13:47:30
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看