1. 程式人生 > >java 對象鎖學習

java 對象鎖學習

test java sleep exceptio rgb start () exc 一個

機制

  鎖機制是用來解決多線程共享資源時產生的沖突問題的。java 為每一個對象關聯一個對象鎖,通常把鎖分為對象鎖和類鎖,他們的本質都是對象鎖,只不過對象鎖關聯的是類的 Object 對象 (java.lang.Object),而類鎖關聯的是類的 Class 對象 java.lang.Class。
  jvm 對每個鎖都有一個計數

  • 若該計數為 0,則鎖沒有被占用,可以被訪問它的線程來持有
  • 一個對象的對象鎖已被某個線程持有,新的線程來訪問時將被掛起,知道持有它的線程釋放該鎖並且計數為 0
  • 一個線程已經持有了某個對象的鎖,該線程再次訪問該對象鎖時可以重入,且計數 +1
  • 一個線程釋放對象鎖時,該鎖的計數 -1,當某個鎖的計數為 0 時鎖被釋放,可以被線程競爭

分類

  • 不管怎麽分類,java 中通過 synchronized 來實現的鎖其本質都是對象鎖
  • java 內部同步機制實現通常有兩種方式,synchronized 修飾方法和語句塊
  • synchronized 關鍵字作用於對象,這個對象可以是類的實例對象,也可以是 Class 對象

    • 類鎖

  1 public class SyncObject {
  2     // 類鎖1:通過static方法加同步鎖
  3     public static synchronized void syncMethod1() {
  4         try {
  5             System.out.println("testMethod1 start!
"); 6 Thread.sleep(3000); 7 } catch (InterruptedException e) { 8 e.printStackTrace(); 9 } 10 System.out.println("testMethod1 end!"); 11 } 12 13 public void syncMethod2() { 14 // 類鎖2:通過同步語句塊傳遞Class類型參數 15 synchronized (SyncObject.class
) { 16 try { 17 System.out.println("testMethod2 start!"); 18 Thread.sleep(3000); 19 } catch (InterruptedException e) { 20 e.printStackTrace(); 21 } finally { 22 System.out.println("testMethod2 end!"); 23 } 24 } 25 } 26 }

類鎖作用於類的 Class 對象,對一個類來說,無論該類有多少個實例,它的靜態變量和靜態方法都只有一份,保存在 Class 對象中。通過對 Class 對象加鎖來實現的同步語句或同步方法,無論該對象的哪個實例來訪問,都需要競爭這個類鎖

  • 對象鎖

  1 public class SyncObject {
  2     // 對象鎖1(方法鎖):通過方法加同步鎖
  3     public synchronized void syncMethod1() {
  4         try {
  5             System.out.println("testMethod1 start!");
  6             Thread.sleep(3000);
  7         } catch (InterruptedException e) {
  8             e.printStackTrace();
  9         }
 10         System.out.println("testMethod1 end!");
 11     }
 12 
 13     public void syncMethod2() {
 14         // 對象鎖2:通過同步語句塊傳遞Object類型參數
 15         synchronized (this) {
 16         // 此處的參數可以是本實例this,也可以是其它實例比如new SyncObject(),傳入哪個實例就對哪個實例加鎖
 17             try {
 18                 System.out.println("testMethod2 start!");
 19                 Thread.sleep(3000);
 20             } catch (InterruptedException e) {
 21                 e.printStackTrace();
 22             } finally {
 23                 System.out.println("testMethod2 end!");
 24             }
 25         }
 26     }
 27 }


對象鎖會對類的實例對象加鎖,每一個 new 操作都會獲得一個新的實例對象,對於 synchronized 修飾的非 static 方法或傳遞參數為實例對象的語句塊,各個實例對象會擁有自己的鎖。

TIPS

    • synchronized 的作用範圍是對象

      • synchronized 修飾的代碼塊需要傳入一個對象參數(這個對象可以使 Class 對象),這個對象參數就是它的作用範圍
      • synchronized 修飾的非靜態方法的作用範圍是 this,即當前對象實例。修飾靜態方法時作用範圍是這個類,即 Class 對象
    • synchronized 的粒度針不可再分


      因為鎖是針對整個對象的,所以當某個對象的鎖被持有後,其它線程不能持有該鎖
      • 當一個線程調用某個對象 a 的 synchronized 方法(a.syncMethod1)在該方法結束之前,該對象的其它 synchronized 方法 (a.syncMethod2..) 都將不能被調用。同步代碼塊 synchronized(a)與 a.syncMethod1 有同樣的作用周期
      • 當一個線程調用某個類 A 的 static synchronized 方法(A.staticSyncMethod1)在該方法結束前,該類的其它 static synchronized 方法(A.staticSyncMethod2..)都將不能被調用
      • 當一個線程調用某個對象 a 的 synchronized 方法(a.syncMethod1)在該方法結束之前,該類的其它 static synchronized 方法 (A.syncMethod2..) 還可以被調用,反之也成立
      • synchronized 的只對它修飾的模塊加鎖

        • 未被 synchronized 修飾的模塊是可以被異步訪問的, 因為線程訪問它的時候並不需要獲取對象鎖

      java 對象鎖學習