Java多線程—-java 對象鎖

來源:互聯網
上載者:User
文章目錄
  • 1. 對象鎖
  • 2. 類鎖
  • 3. synchronized同步塊
  • 4. Lock對象鎖
  • 5. synchronized和lock的區別:

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

1. 對象鎖

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

2. 類鎖

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

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

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

synchronized (xxx.class) {...}synchronized (Class.forName("xxx")) {...}

       若要同時擷取兩種鎖,同時擷取類鎖和對象鎖是允許的,並不會產生任何問題,但使用類鎖時一定要注意,一旦產生類鎖的嵌套擷取的話,就會產生死結,因為每個class在記憶體中都只能產生一個Class執行個體對象。

3. synchronized同步塊3.1. 同步到單一對象鎖

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

package com.zj.lock;import java.util.concurrent.TimeUnit; public class Resource1 {    public void f() {       // other operations should not be locked...       System.out.println(Thread.currentThread().getName()              + ":not synchronized in f()");       synchronized (this) {           for (int i = 0; i < 5; i++) {              System.out.println(Thread.currentThread().getName()                     + ":synchronized in f()");              try {                  TimeUnit.SECONDS.sleep(3);              } catch (InterruptedException e) {                  e.printStackTrace();              }           }       }    }     public void g() {       // other operations should not be locked...       System.out.println(Thread.currentThread().getName()              + ":not synchronized in g()");       synchronized (this) {           for (int i = 0; i < 5; i++) {              System.out.println(Thread.currentThread().getName()                     + ":synchronized in g()");              try {                  TimeUnit.SECONDS.sleep(3);              } catch (InterruptedException e) {                  e.printStackTrace();              }           }       }    }     public void h() {       // other operations should not be locked...       System.out.println(Thread.currentThread().getName()              + ":not synchronized in h()");       synchronized (this) {           for (int i = 0; i < 5; i++) {              System.out.println(Thread.currentThread().getName()                     + ":synchronized in h()");              try {                  TimeUnit.SECONDS.sleep(3);              } catch (InterruptedException e) {                  e.printStackTrace();              }           }       }    }     public static void main(String[] args) {       final Resource1 rs = new Resource1();        new Thread() {           public void run() {              rs.f();           }       }.start();        new Thread() {           public void run() {              rs.g();           }       }.start();        rs.h();    }}

結果:
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

package com.zj.lock;import java.util.concurrent.TimeUnit; public class Resource2 {    private Object syncObject1 = new Object();    private Object syncObject2 = new Object();     public void f() {       // other operations should not be locked...       System.out.println(Thread.currentThread().getName()              + ":not synchronized in f()");       synchronized (this) {           for (int i = 0; i < 5; i++) {              System.out.println(Thread.currentThread().getName()                     + ":synchronized in f()");              try {                  TimeUnit.SECONDS.sleep(3);              } catch (InterruptedException e) {                  e.printStackTrace();              }           }       }    }     public void g() {       // other operations should not be locked...       System.out.println(Thread.currentThread().getName()              + ":not synchronized in g()");       synchronized (syncObject1) {           for (int i = 0; i < 5; i++) {              System.out.println(Thread.currentThread().getName()                     + ":synchronized in g()");              try {                  TimeUnit.SECONDS.sleep(3);              } catch (InterruptedException e) {                  e.printStackTrace();              }           }       }    }     public void h() {       // other operations should not be locked...       System.out.println(Thread.currentThread().getName()              + ":not synchronized in h()");       synchronized (syncObject2) {           for (int i = 0; i < 5; i++) {              System.out.println(Thread.currentThread().getName()                     + ":synchronized in h()");              try {                  TimeUnit.SECONDS.sleep(3);              } catch (InterruptedException e) {                  e.printStackTrace();              }           }       }    }     public static void main(String[] args) {       final Resource2 rs = new Resource2();        new Thread() {           public void run() {              rs.f();           }       }.start();        new Thread() {           public void run() {              rs.g();           }       }.start();        rs.h();    }}

結果:
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

package com.zj.lock;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock; public class Resource3 {    private Lock lock = new ReentrantLock();     public void f() {       // other operations should not be locked...       System.out.println(Thread.currentThread().getName()              + ":not synchronized in f()");       lock.lock();       try {           for (int i = 0; i < 5; i++) {              System.out.println(Thread.currentThread().getName()                     + ":synchronized in f()");              try {                  TimeUnit.SECONDS.sleep(3);              } catch (InterruptedException e) {                  e.printStackTrace();              }           }       } finally {           lock.unlock();       }    }     public void g() {       // other operations should not be locked...       System.out.println(Thread.currentThread().getName()              + ":not synchronized in g()");       lock.lock();       try {           for (int i = 0; i < 5; i++) {              System.out.println(Thread.currentThread().getName()                     + ":synchronized in g()");              try {                  TimeUnit.SECONDS.sleep(3);              } catch (InterruptedException e) {                  e.printStackTrace();              }           }       } finally {           lock.unlock();       }    }     public void h() {       // other operations should not be locked...       System.out.println(Thread.currentThread().getName()              + ":not synchronized in h()");       lock.lock();       try {           for (int i = 0; i < 5; i++) {              System.out.println(Thread.currentThread().getName()                     + ":synchronized in h()");              try {                  TimeUnit.SECONDS.sleep(3);              } catch (InterruptedException e) {                  e.printStackTrace();              }           }       } finally {           lock.unlock();       }    }     public static void main(String[] args) {       final Resource3 rs = new Resource3();        new Thread() {           public void run() {              rs.f();           }       }.start();        new Thread() {           public void run() {              rs.g();           }       }.start();        rs.h();    }

結果:
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

package com.zj.lock;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock; public class Resource4 {    private Lock lock1 = new ReentrantLock();    private Lock lock2 = new ReentrantLock();    private Lock lock3 = new ReentrantLock();     public void f() {       // other operations should not be locked...       System.out.println(Thread.currentThread().getName()              + ":not synchronized in f()");       lock1.lock();       try {           for (int i = 0; i < 5; i++) {              System.out.println(Thread.currentThread().getName()                     + ":synchronized in f()");              try {                  TimeUnit.SECONDS.sleep(3);              } catch (InterruptedException e) {                  e.printStackTrace();              }           }       } finally {           lock1.unlock();       }    }     public void g() {       // other operations should not be locked...       System.out.println(Thread.currentThread().getName()              + ":not synchronized in g()");       lock2.lock();       try {           for (int i = 0; i < 5; i++) {              System.out.println(Thread.currentThread().getName()                     + ":synchronized in g()");              try {                  TimeUnit.SECONDS.sleep(3);              } catch (InterruptedException e) {                  e.printStackTrace();              }           }       } finally {           lock2.unlock();       }    }     public void h() {       // other operations should not be locked...       System.out.println(Thread.currentThread().getName()              + ":not synchronized in h()");       lock3.lock();       try {           for (int i = 0; i < 5; i++) {              System.out.println(Thread.currentThread().getName()                     + ":synchronized in h()");              try {                  TimeUnit.SECONDS.sleep(3);              } catch (InterruptedException e) {                  e.printStackTrace();              }           }       } finally {           lock3.unlock();       }    }     public static void main(String[] args) {       final Resource4 rs = new Resource4();        new Thread() {           public void run() {              rs.f();           }       }.start();        new Thread() {           public void run() {              rs.g();           }       }.start();        rs.h();    }}

結果:
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方法實現。

public boolean tryLock(); //等同於tryLock(0, TimeUnit.SECONDS),不停詢問是否可擷取鎖public boolean tryLock(long timeout,                       TimeUnit unit)                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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.