Java多線程----java 對象鎖

轉載自:http://blog.csdn.net/ymeng_bupt/article/details/6826936

      在併發環境下,解決共享資源衝突問題時,可以考慮使用鎖機制。

1. 對象鎖

      所有對象都自動含有單一的鎖。
     JVM負責跟蹤對象被加鎖的次數。如果一個對象被解鎖,其計數變爲0。在任務(線程)第一次給對象加鎖的時候,計數變爲1。每當這個相同的任務(線程)在此對象上獲得鎖時,計數會遞增。
     只有首先獲得鎖的任務(線程)才能繼續獲取該對象上的多個鎖。
     每當任務離開一個synchronized方法,計數遞減,當計數爲0的時候,鎖被完全釋放,此時別的任務就可以使用此資源。

2. 類鎖

      對於同步靜態方法/靜態變量互斥體,由於一個class不論被實例化多少次,其中的靜態方法和靜態變量在內存中都只由一份。所以,一旦一個靜態的方法被申明爲synchronized。此類所有的實例化對象在調用此方法,共用同一把鎖,我們稱之爲類鎖。一旦一個靜態變量被作爲synchronized block的互斥體。進入此同步區域時,都要先獲得此靜態變量的對象鎖。

      由上述同步靜態方法引申出一個概念,那就是類鎖。其實系統中並不存在什麼類鎖。當一個同步靜態方法被調用時,系統獲取的其實就是代表該類的類對象的對象鎖

      可以嘗試用以下方式獲取類鎖

  1. synchronized (xxx.class) {…}  
  2.   
  3. synchronized (Class.forName(“xxx”)) {…}  
       若要同時獲取兩種鎖,同時獲取類鎖和對象鎖是允許的,並不會產生任何問題,但使用類鎖時一定要注意,一旦產生類鎖的嵌套獲取的話,就會產生死鎖,因爲每個class在內存中都只能生成一個Class實例對象。

3. synchronized同步塊

3.1. 同步到單一對象鎖

        當使用同步塊時,如果方法下的同步塊都同步到一個對象上的鎖,則所有的任務(線程)只能互斥的進入這些同步塊。
        Resource1.java演示了三個線程(包括main線程)試圖進入某個類的三個不同的方法的同步塊中,雖然這些同步塊處在不同的方法中,但由於是同步到同一個對象(當前對象 synchronized (this)),所以對它們的方法依然是互斥的。
Resource1.java

  1. package com.zj.lock;  
  2. import java.util.concurrent.TimeUnit;  
  3.    
  4. public class Resource1 {  
  5.     public void f() {  
  6.        // other operations should not be locked…  
  7.        System.out.println(Thread.currentThread().getName()  
  8.               + ”:not synchronized in f()”);  
  9.        synchronized (this) {  
  10.            for (int i = 0; i < 5; i++) {  
  11.               System.out.println(Thread.currentThread().getName()  
  12.                      + ”:synchronized in f()”);  
  13.               try {  
  14.                   TimeUnit.SECONDS.sleep(3);  
  15.               } catch (InterruptedException e) {  
  16.                   e.printStackTrace();  
  17.               }  
  18.            }  
  19.        }  
  20.     }  
  21.    
  22.     public void g() {  
  23.        // other operations should not be locked…  
  24.        System.out.println(Thread.currentThread().getName()  
  25.               + ”:not synchronized in g()”);  
  26.        synchronized (this) {  
  27.            for (int i = 0; i < 5; i++) {  
  28.               System.out.println(Thread.currentThread().getName()  
  29.                      + ”:synchronized in g()”);  
  30.               try {  
  31.                   TimeUnit.SECONDS.sleep(3);  
  32.               } catch (InterruptedException e) {  
  33.                   e.printStackTrace();  
  34.               }  
  35.            }  
  36.        }  
  37.     }  
  38.    
  39.     public void h() {  
  40.        // other operations should not be locked…  
  41.        System.out.println(Thread.currentThread().getName()  
  42.               + ”:not synchronized in h()”);  
  43.        synchronized (this) {  
  44.            for (int i = 0; i < 5; i++) {  
  45.               System.out.println(Thread.currentThread().getName()  
  46.                      + ”:synchronized in h()”);  
  47.               try {  
  48.                   TimeUnit.SECONDS.sleep(3);  
  49.               } catch (InterruptedException e) {  
  50.                   e.printStackTrace();  
  51.               }  
  52.            }  
  53.        }  
  54.     }  
  55.    
  56.     public static void main(String[] args) {  
  57.        final Resource1 rs = new Resource1();  
  58.    
  59.        new Thread() {  
  60.            public void run() {  
  61.               rs.f();  
  62.            }  
  63.        }.start();  
  64.    
  65.        new Thread() {  
  66.            public void run() {  
  67.               rs.g();  
  68.            }  
  69.        }.start();  
  70.    
  71.        rs.h();  
  72.     }  
  73. }  
結果:
Thread-0:not synchronized in f()
Thread-0:synchronized in f()
main:not synchronized in h()
Thread-1:not synchronized in g()
Thread-0:synchronized in f()
Thread-0:synchronized in f()
Thread-0:synchronized in f()
Thread-0:synchronized in f()
Thread-1:synchronized in g()
Thread-1:synchronized in g()
Thread-1:synchronized in g()
Thread-1:synchronized in g()
Thread-1:synchronized in g()
main:synchronized in h()
main:synchronized in h()
main:synchronized in h()
main:synchronized in h()
main:synchronized in h()

3.2. 同步到多個對象鎖

        Resource1.java演示了三個線程(包括main線程)試圖進入某個類的三個不同的方法的同步塊中,這些同步塊處在不同的方法中,並且是同步到三個不同的對象(synchronized (this),synchronized(syncObject1),synchronized (syncObject2)),所以對它們的方法中的臨界資源訪問是獨立的。
Resource2.java

  1. package com.zj.lock;  
  2. import java.util.concurrent.TimeUnit;  
  3.    
  4. public class Resource2 {  
  5.     private Object syncObject1 = new Object();  
  6.     private Object syncObject2 = new Object();  
  7.    
  8.     public void f() {  
  9.        // other operations should not be locked…  
  10.        System.out.println(Thread.currentThread().getName()  
  11.               + ”:not synchronized in f()”);  
  12.        synchronized (this) {  
  13.            for (int i = 0; i < 5; i++) {  
  14.               System.out.println(Thread.currentThread().getName()  
  15.                      + ”:synchronized in f()”);  
  16.               try {  
  17.                   TimeUnit.SECONDS.sleep(3);  
  18.               } catch (InterruptedException e) {  
  19.                   e.printStackTrace();  
  20.               }  
  21.            }  
  22.        }  
  23.     }  
  24.    
  25.     public void g() {  
  26.        // other operations should not be locked…  
  27.        System.out.println(Thread.currentThread().getName()  
  28.               + ”:not synchronized in g()”);  
  29.        synchronized (syncObject1) {  
  30.            for (int i = 0; i < 5; i++) {  
  31.               System.out.println(Thread.currentThread().getName()  
  32.                      + ”:synchronized in g()”);  
  33.               try {  
  34.                   TimeUnit.SECONDS.sleep(3);  
  35.               } catch (InterruptedException e) {  
  36.                   e.printStackTrace();  
  37.               }  
  38.            }  
  39.        }  
  40.     }  
  41.    
  42.     public void h() {  
  43.        // other operations should not be locked…  
  44.        System.out.println(Thread.currentThread().getName()  
  45.               + ”:not synchronized in h()”);  
  46.        synchronized (syncObject2) {  
  47.            for (int i = 0; i < 5; i++) {  
  48.               System.out.println(Thread.currentThread().getName()  
  49.                      + ”:synchronized in h()”);  
  50.               try {  
  51.                   TimeUnit.SECONDS.sleep(3);  
  52.               } catch (InterruptedException e) {  
  53.                   e.printStackTrace();  
  54.               }  
  55.            }  
  56.        }  
  57.     }  
  58.    
  59.     public static void main(String[] args) {  
  60.        final Resource2 rs = new Resource2();  
  61.    
  62.        new Thread() {  
  63.            public void run() {  
  64.               rs.f();  
  65.            }  
  66.        }.start();  
  67.    
  68.        new Thread() {  
  69.            public void run() {  
  70.               rs.g();  
  71.            }  
  72.        }.start();  
  73.    
  74.        rs.h();  
  75.     }  
  76. }  
結果:
Thread-0:not synchronized in f()
Thread-0:synchronized in f()
main:not synchronized in h()
main:synchronized in h()
Thread-1:not synchronized in g()
Thread-1:synchronized in g()
Thread-0:synchronized in f()
main:synchronized in h()
Thread-1:synchronized in g()
Thread-0:synchronized in f()
main:synchronized in h()
Thread-1:synchronized in g()
Thread-0:synchronized in f()
main:synchronized in h()
Thread-1:synchronized in g()
Thread-0:synchronized in f()
main:synchronized in h()
Thread-1:synchronized in g()

4. Lock對象鎖

      除了使用synchronized外,還可以使用Lock對象來創建臨界區。Resource3.java的演示效果同Resource1.java;Resource4.java的演示效果同Resource2.java。
Resource3.java

  1. package com.zj.lock;  
  2. import java.util.concurrent.TimeUnit;  
  3. import java.util.concurrent.locks.Lock;  
  4. import java.util.concurrent.locks.ReentrantLock;  
  5.    
  6. public class Resource3 {  
  7.     private Lock lock = new ReentrantLock();  
  8.    
  9.     public void f() {  
  10.        // other operations should not be locked…  
  11.        System.out.println(Thread.currentThread().getName()  
  12.               + ”:not synchronized in f()”);  
  13.        lock.lock();  
  14.        try {  
  15.            for (int i = 0; i < 5; i++) {  
  16.               System.out.println(Thread.currentThread().getName()  
  17.                      + ”:synchronized in f()”);  
  18.               try {  
  19.                   TimeUnit.SECONDS.sleep(3);  
  20.               } catch (InterruptedException e) {  
  21.                   e.printStackTrace();  
  22.               }  
  23.            }  
  24.        } finally {  
  25.            lock.unlock();  
  26.        }  
  27.     }  
  28.    
  29.     public void g() {  
  30.        // other operations should not be locked…  
  31.        System.out.println(Thread.currentThread().getName()  
  32.               + ”:not synchronized in g()”);  
  33.        lock.lock();  
  34.        try {  
  35.            for (int i = 0; i < 5; i++) {  
  36.               System.out.println(Thread.currentThread().getName()  
  37.                      + ”:synchronized in g()”);  
  38.               try {  
  39.                   TimeUnit.SECONDS.sleep(3);  
  40.               } catch (InterruptedException e) {  
  41.                   e.printStackTrace();  
  42.               }  
  43.            }  
  44.        } finally {  
  45.            lock.unlock();  
  46.        }  
  47.     }  
  48.    
  49.     public void h() {  
  50.        // other operations should not be locked…  
  51.        System.out.println(Thread.currentThread().getName()  
  52.               + ”:not synchronized in h()”);  
  53.        lock.lock();  
  54.        try {  
  55.            for (int i = 0; i < 5; i++) {  
  56.               System.out.println(Thread.currentThread().getName()  
  57.                      + ”:synchronized in h()”);  
  58.               try {  
  59.                   TimeUnit.SECONDS.sleep(3);  
  60.               } catch (InterruptedException e) {  
  61.                   e.printStackTrace();  
  62.               }  
  63.            }  
  64.        } finally {  
  65.            lock.unlock();  
  66.        }  
  67.     }  
  68.    
  69.     public static void main(String[] args) {  
  70.        final Resource3 rs = new Resource3();  
  71.    
  72.        new Thread() {  
  73.            public void run() {  
  74.               rs.f();  
  75.            }  
  76.        }.start();  
  77.    
  78.        new Thread() {  
  79.            public void run() {  
  80.               rs.g();  
  81.            }  
  82.        }.start();  
  83.    
  84.        rs.h();  
  85.     }  
結果:
Thread-0:not synchronized in f()
Thread-0:synchronized in f()
main:not synchronized in h()
Thread-1:not synchronized in g()
Thread-0:synchronized in f()
Thread-0:synchronized in f()
Thread-0:synchronized in f()
Thread-0:synchronized in f()
main:synchronized in h()
main:synchronized in h()
main:synchronized in h()
main:synchronized in h()
main:synchronized in h()
Thread-1:synchronized in g()
Thread-1:synchronized in g()
Thread-1:synchronized in g()
Thread-1:synchronized in g()
Thread-1:synchronized in g()

Resource4.java

  1. package com.zj.lock;  
  2. import java.util.concurrent.TimeUnit;  
  3. import java.util.concurrent.locks.Lock;  
  4. import java.util.concurrent.locks.ReentrantLock;  
  5.    
  6. public class Resource4 {  
  7.     private Lock lock1 = new ReentrantLock();  
  8.     private Lock lock2 = new ReentrantLock();  
  9.     private Lock lock3 = new ReentrantLock();  
  10.    
  11.     public void f() {  
  12.        // other operations should not be locked…  
  13.        System.out.println(Thread.currentThread().getName()  
  14.               + ”:not synchronized in f()”);  
  15.        lock1.lock();  
  16.        try {  
  17.            for (int i = 0; i < 5; i++) {  
  18.               System.out.println(Thread.currentThread().getName()  
  19.                      + ”:synchronized in f()”);  
  20.               try {  
  21.                   TimeUnit.SECONDS.sleep(3);  
  22.               } catch (InterruptedException e) {  
  23.                   e.printStackTrace();  
  24.               }  
  25.            }  
  26.        } finally {  
  27.            lock1.unlock();  
  28.        }  
  29.     }  
  30.    
  31.     public void g() {  
  32.        // other operations should not be locked…  
  33.        System.out.println(Thread.currentThread().getName()  
  34.               + ”:not synchronized in g()”);  
  35.        lock2.lock();  
  36.        try {  
  37.            for (int i = 0; i < 5; i++) {  
  38.               System.out.println(Thread.currentThread().getName()  
  39.                      + ”:synchronized in g()”);  
  40.               try {  
  41.                   TimeUnit.SECONDS.sleep(3);  
  42.               } catch (InterruptedException e) {  
  43.                   e.printStackTrace();  
  44.               }  
  45.            }  
  46.        } finally {  
  47.            lock2.unlock();  
  48.        }  
  49.     }  
  50.    
  51.     public void h() {  
  52.        // other operations should not be locked…  
  53.        System.out.println(Thread.currentThread().getName()  
  54.               + ”:not synchronized in h()”);  
  55.        lock3.lock();  
  56.        try {  
  57.            for (int i = 0; i < 5; i++) {  
  58.               System.out.println(Thread.currentThread().getName()  
  59.                      + ”:synchronized in h()”);  
  60.               try {  
  61.                   TimeUnit.SECONDS.sleep(3);  
  62.               } catch (InterruptedException e) {  
  63.                   e.printStackTrace();  
  64.               }  
  65.            }  
  66.        } finally {  
  67.            lock3.unlock();  
  68.        }  
  69.     }  
  70.    
  71.     public static void main(String[] args) {  
  72.        final Resource4 rs = new Resource4();  
  73.    
  74.        new Thread() {  
  75.            public void run() {  
  76.               rs.f();  
  77.            }  
  78.        }.start();  
  79.    
  80.        new Thread() {  
  81.            public void run() {  
  82.               rs.g();  
  83.            }  
  84.        }.start();  
  85.    
  86.        rs.h();  
  87.     }  
  88. }  
結果:
Thread-0:not synchronized in f()
Thread-0:synchronized in f()
main:not synchronized in h()
main:synchronized in h()
Thread-1:not synchronized in g()
Thread-1:synchronized in g()
Thread-0:synchronized in f()
main:synchronized in h()
Thread-1:synchronized in g()
Thread-0:synchronized in f()
main:synchronized in h()
Thread-1:synchronized in g()
Thread-0:synchronized in f()
main:synchronized in h()
Thread-1:synchronized in g()
Thread-0:synchronized in f()
main:synchronized in h()

Thread-1:synchronized in g()

     另外,ReentrantLock可定時和可輪詢的鎖獲取模式由tryLock方法實現。

  1. public boolean tryLock(); //等同於tryLock(0, TimeUnit.SECONDS),不停詢問是否可獲取鎖  
  2. public boolean tryLock(long timeout,  
  3.                        TimeUnit unit)  
  4.                 throws InterruptedException    //timeout - 等待鎖的時間,unit - timeout 參數的時間單位   

5. synchronized和lock的區別:

      Lock 的鎖定是通過代碼實現的,而 synchronized 是在 JVM 層面上實現的。

      synchronized 在鎖定時如果方法塊拋出異常,JVM 會自動將鎖釋放掉,不會因爲出了異常沒有釋放鎖造成線程死鎖。但是 Lock 的話就享受不到 JVM 帶來自動的功能,出現異常時必須在 finally 將鎖釋放掉,否則將會引起死鎖。

      在資源競爭不是很激烈的情況下,偶爾會有同步的情形下,synchronized是很合適的。原因在於,編譯程序通常會儘可能的進行優化synchronize,另外可讀性非常好,不管用沒用過5.0多線程包的程序員都能理解。

      ReentrantLock:

      ReentrantLock提供了多樣化的同步,比如有時間限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在資源競爭不激烈的情形下,性能稍微比synchronized差點點。但是當同步非常激烈的時候,synchronized的性能一下子能下降好幾十倍。而ReentrantLock確還能維持常態。

      Atomic:

      和上面的類似,不激烈情況下,性能比synchronized略遜,而激烈的時候,也能維持常態。激烈的時候,Atomic的性能會優於ReentrantLock一倍左右。但是其有一個缺點,就是隻能同步一個值,一段代碼中只能出現一個Atomic的變量,多於一個同步無效。因爲他不能在多個Atomic之間同步。

      關於synchronized和lock的詳細區別請看http://www.ibm.com/developerworks/cn/java/j-jtp10264/index.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章