瘋狂

          STANDING ON THE SHOULDERS OF GIANTS
          posts - 481, comments - 486, trackbacks - 0, articles - 1
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          synchronized 和 volatile

          Posted on 2010-01-14 14:36 瘋狂 閱讀(1098) 評論(0)  編輯  收藏 所屬分類: java
           

          為了確保可以在線程之間以受控方式共享數據,Java 語言提供了兩個關鍵字:synchronizedvolatile。

          Synchronized 有兩個重要含義:它確保了一次只有一個線程可以執行代碼的受保護部分(互斥,mutual exclusion 或者說 mutex),而且它確保了一個線程更改的數據對于其它線程是可見的(更改的可見性)。

          如果沒有同步,數據很容易就處于不一致狀態。例如,如果一個線程正在更新兩個相關值(比如,粒子的位置和速率),而另一個線程正在讀取這兩個值,有可能在第一個線程只寫了一個值,還沒有寫另一個值的時候,調度第二個線程運行,這樣它就會看到一個舊值和一個新值。同步讓我們可以定義必須原子地運行的代碼塊,這樣對于其他線程而言,它們要么都執行,要么都不執行。

          同步的原子執行或互斥方面類似于其它操作環境中的臨界段的概念。


          同步可以讓我們確保線程看到一致的內存視圖。

          處理器可以使用高速緩存加速對內存的訪問(或者編譯器可以將值存儲到寄存器中以便進行更快的訪問)。在一些多處理器體系結構上,如果在一個處理器的高速緩存中修改了內存位置,沒有必要讓其它處理器看到這一修改,直到刷新了寫入器的高速緩存并且使讀取器的高速緩存無效。

          這表示在這樣的系統上,對于同一變量,在兩個不同處理器上執行的兩個線程可能會看到兩個不同的值!這聽起來很嚇人,但它很常見。它只是表示在訪問其它線程使用或修改的數據時,必須遵循某些規則。

          Volatile 比同步更簡單,只適合于控制對基本變量(整數、布爾變量等)的單個實例的訪問。當一個變量被聲明成 volatile,任何對該變量的寫操作都會繞過高速緩存,直接寫入主內存,而任何對該變量的讀取也都繞過高速緩存,直接取自主內存。這表示所有線程在任何時候看到的 volatile 變量值都相同。

          如果沒有正確的同步,線程可能會看到舊的變量值,或者引起其它形式的數據損壞。

           
          簡單的同步示例 第 6 頁(共12 頁)


          使用 synchronized 塊可以讓您將一組相關更新作為一個集合來執行,而不必擔心其它線程中斷或看到計算的中間結果。以下示例代碼將打印“1 0”或“0 1”。如果沒有同步,它還會打印“1 1”(或“0 0”,隨便您信不信)。

          
          public class SyncExample {
          private static lockObject = new Object();
          private static class Thread1 extends Thread {
          public void run() {
          synchronized (lockObject) {
          x = y = 0;
          System.out.println(x);
          }
          }
          }
          private static class Thread2 extends Thread {
          public void run() {
          synchronized (lockObject) {
          x = y = 1;
          System.out.println(y);
          }
          }
          }
          public static void main(String[] args) {
          new Thread1().run();
          new Thread2().run();
          }
          }
          
          

          在這兩個線程中都必須使用同步,以便使這個程序正確工作。

          Volatile 對于確保每個線程看到最新的變量值非常有用,但有時我們需要保護比較大的代碼片段,如涉及更新多個變量的片段。

          同步使用監控器(monitor)或鎖的概念,以協調對特定代碼塊的訪問。

          每個 Java 對象都有一個相關的鎖。同一時間只能有一個線程持有 Java 鎖。當線程進入 synchronized 代碼塊時,線程會阻塞并等待,直到鎖可用,當它可用時,就會獲得這個鎖,然后執行代碼塊。當控制退出受保護的代碼塊時,即到達了代碼塊末尾或者拋出了沒有在 synchronized 塊中捕獲的異常時,它就會釋放該鎖。

          這樣,每次只有一個線程可以執行受給定監控器保護的代碼塊。從其它線程的角度看,該代碼塊可以看作是原子的,它要么全部執行,要么根本不執行。

          主站蜘蛛池模板: 凉山| 略阳县| 太原市| 吴桥县| 朝阳县| 北流市| 土默特右旗| 孝昌县| 团风县| 新津县| 临沧市| 江孜县| 稻城县| 广宁县| 涟源市| 文登市| 咸丰县| 玉山县| 镶黄旗| 富民县| 农安县| 湟源县| 枣阳市| 西吉县| 长兴县| 民勤县| 德格县| 庆阳市| 上杭县| 崇州市| 武功县| 循化| 五莲县| 罗平县| 咸阳市| 肃北| 焉耆| 成都市| 黄冈市| 永丰县| 静安区|