類別鎖和物件鎖是否會衝突?物件鎖和私有鎖是否會衝突?透過實例來進行說明。
一、相關約定
為了明確後文的描述,先對本文涉及到的鎖的相關定義作如下約定:
1. 類別鎖:在程式碼中的方法上加了static和synchronized的鎖,或synchronized(xxx.class)的程式碼段,如下文的increament();
2.物件鎖:在程式碼中的方法上加了synchronized的鎖,或是synchronized(this)的程式碼段,如下文的synOnMethod ()和synInMethod();
3.私有鎖:在類別內部宣告一個私有屬性如private Object lock,在需要加鎖的程式碼區段synchronized(lock),如下文的synMethodWithObj()。
二、測試程式碼
1.編寫一個啟動類別ObjectLock
public class ObjectLock { public static void main(String[] args) { System.out.println("start time = " + System.currentTimeMillis()+"ms"); LockTestClass test = new LockTestClass(); for (int i = 0; i < 3; i++) { Thread thread = new ObjThread(test, i); thread.start(); } } }
2.編寫一個執行緒類別ObjThread,用於啟動同步方法(注意它的run方法可能會調整以進行不同的測試)
public class ObjThread extends Thread { LockTestClass lock; int i = 0; public ObjThread(LockTestClass lock, int i) { this.lock = lock; this.i = i; } public void run() { //无锁方法 // lock.noSynMethod(this.getId(),this); //对象锁方法1,采用synchronized synInMethod的方式 lock.synInMethod(); //对象锁方法2,采用synchronized(this)的方式 // lock.synOnMethod(); //私有锁方法,采用synchronized(object)的方式 // lock.synMethodWithObj(); //类锁方法,采用static synchronized increment的方式 LockTestClass.increment(); } }
3 .再寫一個鎖的測試類別LockTestClass,包括各種加鎖方法
public class LockTestClass { //用于类锁计数 private static int i = 0; //私有锁 private Object object = new Object(); /** * <p> * 无锁方法 * * @param threadID * @param thread */ public void noSynMethod(long threadID, ObjThread thread) { System.out.println("nosyn: class obj is " + thread + ", threadId is" + threadID); } /** * 对象锁方法1 */ public synchronized void synOnMethod() { System.out.println("synOnMethod begins" + ", time = " + System.currentTimeMillis() + "ms"); try { Thread.sleep(2000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("synOnMethod ends"); } /** * 对象锁方法2,采用synchronized (this)来加锁 */ public void synInMethod() { synchronized (this) { System.out.println("synInMethod begins" + ", time = " + System.currentTimeMillis() + "ms"); try { Thread.sleep(2000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("synInMethod ends"); } } /** * 对象锁方法3 */ public void synMethodWithObj() { synchronized (object) { System.out.println("synMethodWithObj begins" + ", time = " + System.currentTimeMillis() + "ms"); try { Thread.sleep(2000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("synMethodWithObj ends"); } } /** * 类锁 */ public static synchronized void increament() { System.out.println("class synchronized. i = " + i + ", time = " + System.currentTimeMillis() + "ms"); i++; try { Thread.sleep(2000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("class synchronized ends."); } }
三、測試結果
1.測試類別鎖定和物件鎖,ObjectThread的run方法修改如下:
public void run() { //无锁方法 // lock.noSynMethod(this.getId(),this); //对象锁方法1,采用synchronized synInMethod的方式 lock.synInMethod(); //对象锁方法2,采用synchronized(this)的方式 // lock.synOnMethod(); //私有锁方法,采用synchronized(object)的方式 // lock.synMethodWithObj(); //类锁方法,采用static synchronized increment的方式 LockTestClass.increament(); }
終端輸出:
start time = 1413101360231ms synInMethod begins, time = 1413101360233ms synInMethod ends class synchronized. i = 0, time = 1413101362233ms synInMethod begins, time = 1413101362233ms class synchronized ends. synInMethod ends class synchronized. i = 1, time = 1413101364233ms synInMethod begins, time = 1413101364233ms class synchronized ends. synInMethod ends class synchronized. i = 2, time = 1413101366234ms class synchronized ends.
reee
可以看到物件鎖定方法(synInMothod)第一次啟動時比類別鎖定方法(increament)快2秒,這是因為在synInMehtod執行時sleep了2秒再執行的increament,而這兩個方法共用一個線程,所以會慢2秒,如果increament在run放到synInMethod前面,那麼第一次啟動時就是increament快2秒。 而當類別鎖定方法啟動時,另一個執行緒時的物件鎖定方法也幾乎同時啟動,說明二者使用的並非同一個鎖,不會產生競爭。 結論:類別鎖和物件鎖定不會產生競爭,二者的加鎖方法不會互相影響。 2.私有鎖和物件鎖,ObjectThread的run方法修改如下:public void run() { //无锁方法 // lock.noSynMethod(this.getId(),this); //对象锁方法1,采用synchronized synInMethod的方式 lock.synInMethod(); //对象锁方法2,采用synchronized(this)的方式 // lock.synOnMethod(); //私有锁方法,采用synchronized(object)的方式 lock.synMethodWithObj(); //类锁方法,采用static synchronized increment的方式 // LockTestClass.increament(); }
start time = 1413121912406ms synInMethod begins, time = 1413121912407ms. synInMethod ends. synMethodWithObj begins, time = 1413121914407ms synInMethod begins, time = 1413121914407ms. synInMethod ends. synMethodWithObj ends synInMethod begins, time = 1413121916407ms. synMethodWithObj begins, time = 1413121916407ms synInMethod ends. synMethodWithObj ends synMethodWithObj begins, time = 1413121918407ms synMethodWithObj ends
public void run() { //无锁方法 // lock.noSynMethod(this.getId(),this); //对象锁方法1,采用synchronized synInMethod的方式 lock.synInMethod(); //对象锁方法2,采用synchronized(this)的方式 lock.synOnMethod(); //私有锁方法,采用synchronized(object)的方式 // lock.synMethodWithObj(); //类锁方法,采用static synchronized increment的方式 // LockTestClass.increament(); }
start time = 1413102913278ms synInMethod begins, time = 1413102913279ms synInMethod ends synInMethod begins, time = 1413102915279ms synInMethod ends synOnMethod begins, time = 1413102917279ms synOnMethod ends synInMethod begins, time = 1413102919279ms synInMethod ends synOnMethod begins, time = 1413102921279ms synOnMethod ends synOnMethod begins, time = 1413102923279ms synOnMethod ends