java 對象鎖學習
阿新 • • 發佈:2017-09-04
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 修飾的代碼塊需要傳入一個對象參數(這個對象可以使 Class 對象),這個對象參數就是它的作用範圍
- synchronized 修飾的非靜態方法的作用範圍是 this,即當前對象實例。修飾靜態方法時作用範圍是這個類,即 Class 對象
synchronized 的作用範圍是對象
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 對象鎖學習