<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之旅 廣告
                ## 10 有福同享,有難同當—原子性 > 耐心和恒心總會得到報酬的。 > ——愛因斯坦 從本節開始,我們進入新一章的學習–《并發的問題和原因詳解》。關于如何實現并發,前文已經做了詳盡的講解。現在我們可以輕松的啟動多個線程來完成工作,但是同樣也會面臨各種各樣的問題。例如前一節的例子,學生和老師都要訪問任務列表這個共享資源的時候,我們的程序必須加上同步才能正常運行。其實這只是問題之一,還有更多的問題等待著我們。 所有并發程序都需要保證線程的安全性,那么什么是線程的安全性呢?其實很難給出一個非常正式的定義。有些定義雖然沒有錯誤,但好像說的又是廢話。例如,線程安全是指一個類在多線程并發的情況下可以安全使用。這種定義沒有任何指導價值。 其實線程安全中的安全,是指程序的正確性。程序不但要在單線程的時候保證正確,在多線程并發的時候也要保證程序計算的正確性。比如我們最初幾版抄寫單詞的代碼,只有一個線程運行是正確的,但多線程并發會使得抄寫次數超過要求次數,也就是說程序運行結果不正確,那么就是非線程安全的。最后一版我們經過修改,確保多線程并行,抄寫次數的總和等于要求的次數,那么就是線程安全的。所以我們線程安全可以這樣定義:某個類,在多線程并發訪問時,始終能夠確保運行的正確性,那么這個類就是線程安全的。 確保線程安全,會面對諸多挑戰。在本章中,我們將分析多線程開發中會遇到的典型問題以及其產生的根本原因。解決了這些問題,也就保證了線程安全。最后為了幫助大家對多線程問題產生的原因有更為深入的理解,我會用一節來介紹Java的內存模型。只有深刻理解了我們所使用語言的底層原理,才能夠從容應對任何問題,萬變不離其宗。 ## 1\. 并發編程的三大特性 所有講并發編程的書籍都會講到并發編程的三大特性,這是并發編程中所有問題的根源,我們只有深刻理解了這三大特性,才不會編寫出漏洞百出的并發程序,才不會遇到問題時無從下手,才不會對自己的程序沒有信心。 這三大特性是: 1、原子性 所有操作要么全部成功,要么全部失敗。 2、可見性 一個線程對變量進行了修改,另外一個線程能夠立刻讀取到此變量的最新值。 3、有序性 代碼在執行階段,并不一定和你的編寫順序一致。 以上是對三大特性的簡單解釋。不理解也沒有關系,本章中會一一進行講解。在本節中我們重點來看原子性。 ## 2\. 什么是原子性 原子性是三大特性中最好理解的一個。只要你做過程序開發,應該都會聽說過原子性。如果沒有,那么至少聽說過事務吧?原子性是事務的四大特性—ACID 之一,并且位居首位,可見其重要性。那么到底什么是原子性呢?原子性的重點在原子上。如果你的初中物理和化學,還沒有因全身心投入到計算機行業,而全部還給老師,那么應該還記得原子在化學反應中不可以再分割。其實所謂的原子性就是不可分割性。做為一個整體的N次操作不可分割,一榮俱榮,一損俱損。 我們抄寫單詞的例子中有三步操作。第一步,查詢剩余抄寫次數。第二步,如果剩余次數大于零,把次數-1。第三步,把新的剩余次數更新到 punishment 對象中。這三步操作是原子操作。在操作期間,別的線程不能讀取剩余抄寫次數,以免別的取到更新前的舊值而重復抄寫。這里我們引入一個新的概念:競態條件。 ## 3\. 競態條件 競態條件是指,在多線程的情況下,由于多個線程執行的時序不同,而出現不正確的結果。上文的例子是典型的先檢查后執行,這也是最常見的競態條件類型。上面例子的問題出現在第 2、3 步操作依賴于第1步的檢查,而第一步的檢查結果并不能保證在執行 2、3 步的時候依舊有效。這是因為其它線程可能在你在執行完第一步時已經改變了剩余次數。此時 2,3 步依舊會按照已經失效的檢查結果繼續執行,那么線程安全問題就出現了。 其實現實中,我們也會經常遇到競態條件。舉個例子,你的室友中午要出去辦事,可能趕不上下午第一節課。他拜托你,如果老師點名時他還沒回來,幫他答一下到。下午第一節課果然老師點名了,眼看就要點到你的室友,你環顧了下四周,確認室友沒有趕回來,然后緊張的等待老師點到室友的名字。老師又點了幾個名字后,終于點到了你室友的名字。你故作鎮定,沉穩、大方的喊了聲:到!但令人尷尬的是,幾乎同時,教室后面也傳出了一聲鏗鏘有力的到!你回頭一看,就這幾秒鐘的時間,室友已經趕回了教室,從后門溜進來坐在了最后一排。 ![圖片描述](https://img.mukewang.com/5d898a220001341011200551.jpg) 這就是競態條件,你觀察到室友沒有來上課的結果,在你替室友答到的時候已經失效了。但你并不知道,依舊按照失效的觀測結果執行答到。最后造成了尷尬的局面。你們精心設計好的程序執行錯誤,穿幫了。這多像我們精心編寫一段并發程序,信心滿滿的去執行,卻發現執行結果是錯誤的。 競態條件并不一定會造成問題,正如我們前面的程序,在第一版改進后,抄寫 1000 次單詞,并不會出現錯誤。但是抄寫 1 萬次以上時,就會出現問題。這是因為在多線程執行時,不同線程的不同步驟在特定時序執行才會出問題。而執行次數越多就越可能碰上導致出錯的特定時序。回到例子,如果你的室友沒有偏偏趕在你觀察和點名之前那個時間段回到教室,就不會出現任何問題。 單例是個經典的話題。僅是單例有幾種寫法,都夠程序員們爭論幾天。其中有一種寫法如下: ~~~java public class Singleton { private static Singleton singleton = null; private Singleton() { } public static Singleton getInstance() { if(singleton==null){ singleton = new Singleton(); } return singleton; } } ~~~ 這段代碼在非并發的情況下沒有任何問題。但是在并發的情況下,因為競態條件有可能引發錯誤。如果線程 A 在判斷 singleton 為空并且創建 singleton 對象之前,線程B也開始執行這段代碼,它同樣會判斷 singleton 為空去創建 singleton,這樣本來的單例卻變成了雙例,和我們期望的正確結果不一致。 ## 3\. 總結 如果在需要保證原子性的一組操作中,有競態條件產生,那么就會出現線程安全的問題。我們可以通過為原子操作加鎖或者使用原子變量來解決。原子變量在 java.util.concurrent.atomic 包中,它提供了一系列的原子操作。后面的章節我們會深入講解原子變量的使用和原理。
                  <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>

                              哎呀哎呀视频在线观看