隨筆 - 312, 文章 - 14, 評論 - 1393, 引用 - 0
          數據加載中……

          Java多線程初學者指南(11):使用Synchronized塊同步方法

          本文為原創,如需轉載,請注明作者和出處,謝謝!

          上一篇:Java多線程初學者指南(10):使用Synchronized關鍵字同步類方法

              synchronized關鍵字有兩種用法。第一種就是在《使用Synchronized關鍵字同步類方法》一文中所介紹的直接用在方法的定義中。另外一種就是synchronized塊。我們不僅可以通過synchronized塊來同步一個對象變量。也可以使用synchronized塊來同步類中的靜態方法和非靜態方法。

          synchronized塊的語法如下:

          public void method()
          {
              … …
              
          synchronized(表達式)
              {
                  … …
              }
          }

          一、非靜態類方法的同步   

          《使用Synchronized關鍵字同步類方法》一文中我們知道使用synchronized關鍵字來定義方法就會鎖定類中所有使用synchronzied關鍵字定義的靜態方法或非靜態方法,但這并不好理解。而如果使用synchronized塊來達到同樣的效果,就不難理解為什么會產生這種效果了。如果想使用synchronized塊來鎖定類中所有的同步非靜態方法,需要使用this做為synchronized塊的參數傳入synchronized塊國,代碼如下:

          通過synchronized塊同步非靜態方法

            001  public class SyncBlock
            
          002  {
            
          003      public void method1()
            
          004      {
            
          005          synchronized(this)  // 相當于對method1方法使用synchronized關鍵字
            006          {
            
          007              … …
            
          008          }
            
          009      }
            
          010      public void method2()
            
          011      {
            
          012          synchronized(this)  // 相當于對method2方法使用synchronized關鍵字
            013          {
            
          014              … …
            
          015          }
            
          016      }
            
          017      public synchronized void method3()  
            
          018      {
            
          019          … …
            
          020      }
            
          021  }

          在上面的代碼中的method1method2方法中使用了synchronized塊。而第017行的method3方法仍然使用synchronized關鍵字來定義方法。在使用同一個SyncBlock類實例時,這三個方法只要有一個正在執行,其他兩個方法就會因未獲得同步鎖而被阻塞。在使用synchronized塊時要想達到和synchronized關鍵字同樣的效果,必須將所有的代碼都寫在synchronized塊中,否則,將無法使當前方法中的所有代碼和其他的方法同步。

          除了使用this做為synchronized塊的參數外,還可以使用SyncBlock.this作為synchronized塊的參數來達到同樣的效果。

          在內類(InnerClass)的方法中使用synchronized塊來時,this只表示內類,和外類(OuterClass)沒有關系。但內類的非靜態方法可以和外類的非靜態方法同步。如在內類InnerClass中加一個method4方法,并使method4方法和SyncBlock的三個方法同步,代碼如下:

          使內類的非靜態方法和外類的非靜態方法同步

          public class SyncBlock
          {
              … …
              class InnerClass
              {
                 
          public void method4()
                  {
                     
          synchronized(SyncBlock.this)
                      {
                          … … 
                      }
                  }
              }
              … …
          }

          在上面SyncBlock類的新版本中,InnerClass類的method4方法和SyncBlock類的其他三個方法同步,因此,method1method2、method3method4四個方法在同一時間只能有一個方法執行。

          Synchronized塊不管是正常執行完,還是因為程序出錯而異常退出synchronized塊,當前的synchronized塊所持有的同步鎖都會自動釋放。因此,在使用synchronized塊時不必擔心同步鎖的釋放問題。

          二、靜態類方法的同步

          由于在調用靜態方法時,對象實例不一定被創建。因此,就不能使用this來同步靜態方法,而必須使用Class對象來同步靜態方法。代碼如下:

          通過synchronized塊同步靜態方法

             public class StaticSyncBlock
             {
                 
          public static void method1()
                 {
                     
          synchronized(StaticSyncBlock.class)  
                     {
                         … …
                     }
                 }
                 
          public static synchronized void method2()  
                 {
                     … …
                 }
             }

              在同步靜態方法時可以使用類的靜態字段class來得到Class對象。在上例中method1method2方法同時只能有一個方法執行。除了使用class字段得到Class對象外,還可以使用實例的getClass方法來得到Class對象。上例中的代碼可以修改如下:

          使用getClass方法得到Class對象

          public class StaticSyncBlock
          {
              public static StaticSyncBlock instance; 
              public StaticSyncBlock()
              {
                  instance 
          = this;
              }
              public static void method1()
              {
                 
          synchronized(instance.getClass())
                 {
                      
                 }
              }
               
          }

          在上面代碼中通過一個public的靜態instance得到一個StaticSyncBlock類的實例,并通過這個實例的getClass方法得到了Class對象(一個類的所有實例通過getClass方法得到的都是同一個Class對象,因此,調用任何一個實例的getClass方法都可以)。我們還可以通過Class對象使不同類的靜態方法同步,如Test類的靜態方法methodStaticSyncBlock類的兩個靜態方法同步,代碼如下:

          Test類的method方法和StaticSyncBlock類的method1、method2方法同步

             public class Test
             {
                 
          public static void method()
                 {
                     
          synchronized(StaticSyncBlock.class)
                     {
                          
                     }
                 }
             }

          注意:在使用synchronized塊同步類方法時,非靜態方法可以使用this來同步,而靜態方法必須使用Class對象來同步。它們互不影響。當然,也可以在非靜態方法中使用Class對象來同步靜態方法。但在靜態方法中不能使用this來同步非靜態方法。這一點在使用synchronized塊同步類方法時應注意。

          下一篇:Java多線程初學者指南(12):使用Synchronized塊同步變量





          Android開發完全講義(第2版)(本書版權已輸出到臺灣)

          http://product.dangdang.com/product.aspx?product_id=22741502



          Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


          新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

          posted on 2009-03-22 21:15 銀河使者 閱讀(11349) 評論(1)  編輯  收藏 所屬分類: java 、 原創 、多線程

          評論

          # re: Java多線程初學者指南(11):使用Synchronized塊同步方法[未登錄]  回復  更多評論   

          看了這里的同步機制,很受啟發,特別是對靜態與非靜態的分開細致的分析,讓我茅塞頓開,呵呵,解決了個把問題啊~
          謝謝博主啊~?。?
          2010-08-02 17:10 | Kelvin
          主站蜘蛛池模板: 临清市| 信宜市| 拜城县| 克东县| 广平县| 晴隆县| 德安县| 仁怀市| 定西市| 青阳县| 泽普县| 樟树市| 仙桃市| 汶川县| 九龙县| 搜索| 皋兰县| 清水县| 福贡县| 隆安县| 远安县| 茌平县| 如皋市| 故城县| 灵武市| 泸水县| 柳河县| 姚安县| 许昌市| 鸡泽县| 文登市| 南皮县| 罗田县| 霍城县| 齐齐哈尔市| 建德市| 江陵县| 古蔺县| 加查县| 琼结县| 志丹县|