<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] ## 鎖優化 這里的鎖優化主要是指虛擬機對 synchronized 的優化。 ### 自旋鎖 互斥同步的進入阻塞狀態的開銷都很大,應該盡量避免。在許多應用中,共享數據的鎖定狀態只會持續很短的一段時間。自旋鎖的思想是讓一個線程在請求一個共享數據的鎖時執行忙循環(自旋)一段時間,如果在這段時間內能獲得鎖,就可以避免進入阻塞狀態。 自旋鎖雖然能避免進入阻塞狀態從而減少開銷,但是它需要進行忙循環操作占用 CPU 時間,它只適用于共享數據的鎖定狀態很短的場景。 在 JDK 1.6 中引入了自適應的自旋鎖。自適應意味著自旋的次數不再固定了,而是由前一次在同一個鎖上的自旋次數及鎖的擁有者的狀態來決定。 ### 鎖消除 鎖消除是指對于被檢測出不可能存在競爭的共享數據的鎖進行消除。 鎖消除主要是通過**逃逸分析**來支持,如果堆上的共享數據不可能逃逸出去被其它線程訪問到,那么就可以把它們當成私有數據對待,也就可以將它們的鎖進行消除。 對于一些看起來沒有加鎖的代碼,其實隱式的加了很多鎖。例如下面的字符串拼接代碼就隱式加了鎖: ~~~java public static String concatString(String s1, String s2, String s3) { return s1 + s2 + s3; } ~~~ String 是一個不可變的類,編譯器會對 String 的拼接自動優化。在 JDK 1.5 之前,會轉化為 StringBuffer 對象的連續 append() 操作: ~~~java public static String concatString(String s1, String s2, String s3) { StringBuffer sb = new StringBuffer(); sb.append(s1); sb.append(s2); sb.append(s3); return sb.toString(); } ~~~ 每個 append() 方法中都有一個同步塊。虛擬機觀察變量 sb,很快就會發現它的動態作用域被限制在 concatString() 方法內部。也就是說,sb 的所有引用永遠不會“逃逸”到 concatString() 方法之外,其他線程無法訪問到它,因此可以進行消除。 ### 鎖粗化 如果一系列的連續操作都對同一個對象反復加鎖和解鎖,頻繁的加鎖操作就會導致性能損耗。 上一節的示例代碼中連續的 append() 方法就屬于這類情況。如果虛擬機探測到由這樣的一串零碎的操作都對同一個對象加鎖,將會把加鎖的范圍擴展(粗化)到整個操作序列的外部。對于上一節的示例代碼就是擴展到第一個 append() 操作之前直至最后一個 append() 操作之后,這樣只需要加鎖一次就可以了。 ### 輕量級鎖 JDK 1.6 引入了偏向鎖和輕量級鎖,從而讓鎖擁有了四個狀態:無鎖狀態(unlocked)、偏向鎖狀態(biasble)、輕量級鎖狀態(lightweight locked)和重量級鎖狀態(inflated)。 以下是 HotSpot 虛擬機對象頭的內存布局,這些數據被稱為 mark word。其中 tag bits 對應了五個狀態,這些狀態在右側的 state 表格中給出,應該注意的是 state 表格不是存儲在對象頭中的。除了 marked for gc 狀態,其它四個狀態已經在前面介紹過了。 [![](https://github.com/frank-lam/fullstack-tutorial/raw/master/notes/JavaArchitecture/assets/bb6a49be-00f2-4f27-a0ce-4ed764bc605c-1534158631668.png)](https://github.com/frank-lam/fullstack-tutorial/blob/master/notes/JavaArchitecture/assets/bb6a49be-00f2-4f27-a0ce-4ed764bc605c-1534158631668.png) 下圖左側是一個線程的虛擬機棧,其中有一部分稱為 Lock Record 的區域,這是在輕量級鎖運行過程創建的,用于存放鎖對象的 Mark Word。而右側就是一個鎖對象,包含了 Mark Word 和其它信息。 [![](https://github.com/frank-lam/fullstack-tutorial/raw/master/notes/JavaArchitecture/assets/051e436c-0e46-4c59-8f67-52d89d656182-1534158643175.png)](https://github.com/frank-lam/fullstack-tutorial/blob/master/notes/JavaArchitecture/assets/051e436c-0e46-4c59-8f67-52d89d656182-1534158643175.png) 輕量級鎖是相對于傳統的重量級鎖而言,它使用 CAS 操作來避免重量級鎖使用互斥量的開銷。對于絕大部分的鎖,在整個同步周期內都是不存在競爭的,因此也就不需要都使用互斥量進行同步,可以先采用 CAS 操作進行同步,如果 CAS 失敗了再改用互斥量進行同步。 當嘗試獲取一個鎖對象時,如果鎖對象標記為 0 01,說明鎖對象的鎖未鎖定(unlocked)狀態。此時虛擬機在當前線程棧中創建 Lock Record,然后使用 CAS 操作將對象的 Mark Word 更新為 Lock Record 指針。如果 CAS 操作成功了,那么線程就獲取了該對象上的鎖,并且對象的 Mark Word 的鎖標記變為 00,表示該對象處于輕量級鎖狀態。 [![](https://github.com/frank-lam/fullstack-tutorial/raw/master/notes/JavaArchitecture/assets/baaa681f-7c52-4198-a5ae-303b9386cf47-1534158703049.png)](https://github.com/frank-lam/fullstack-tutorial/blob/master/notes/JavaArchitecture/assets/baaa681f-7c52-4198-a5ae-303b9386cf47-1534158703049.png) 如果 CAS 操作失敗了,虛擬機首先會檢查對象的 Mark Word 是否指向當前線程的虛擬機棧,如果是的話說明當前線程已經擁有了這個鎖對象,那就可以直接進入同步塊繼續執行,否則說明這個鎖對象已經被其他線程線程搶占了。如果有兩條以上的線程爭用同一個鎖,那輕量級鎖就不再有效,要膨脹為重量級鎖。 ### 偏向鎖 偏向鎖的思想是偏向于讓第一個獲取鎖對象的線程,這個線程在之后獲取該鎖就不再需要進行同步操作,甚至連 CAS 操作也不再需要。 當鎖對象第一次被線程獲得的時候,進入偏向狀態,標記為 1 01。同時使用 CAS 操作將線程 ID 記錄到 Mark Word 中,如果 CAS 操作成功,這個線程以后每次進入這個鎖相關的同步塊就不需要再進行任何同步操作。 當有另外一個線程去嘗試獲取這個鎖對象時,偏向狀態就宣告結束,此時撤銷偏向(Revoke Bias)后恢復到未鎖定狀態或者輕量級鎖狀態。 [![](https://github.com/frank-lam/fullstack-tutorial/raw/master/notes/JavaArchitecture/assets/390c913b-5f31-444f-bbdb-2b88b688e7ce-1534158712253.jpg)](https://github.com/frank-lam/fullstack-tutorial/blob/master/notes/JavaArchitecture/assets/390c913b-5f31-444f-bbdb-2b88b688e7ce-1534158712253.jpg) <br> ## 多線程開發良好的實踐 * 給線程起個有意義的名字,這樣可以方便找 Bug。 * 縮小同步范圍,例如對于 synchronized,應該盡量使用同步塊而不是同步方法。 * 多用同步類少用 wait() 和 notify()。首先,CountDownLatch, CyclicBarrier, Semaphore 和 Exchanger 這些同步類簡化了編碼操作,而用 wait() 和 notify() 很難實現對復雜的控制流;其次,這些同步類是由最好的企業編寫和維護,在后續的 JDK 中還會不斷優化和完善,使用這些更高等級的同步工具你的程序可以不費吹灰之力獲得優化。 * 多用并發集合少用同步集合,例如應該使用 ConcurrentHashMap 而不是 Hashtable。 * 使用本地變量和不可變類來保證線程安全。 * 使用線程池而不是直接創建 Thread 對象,這是因為創建線程代價很高,線程池可以有效地利用有限的線程來啟動任務。 * 使用 BlockingQueue 實現生產者消費者問題。
                  <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>

                              哎呀哎呀视频在线观看