Java synchronized 详解
下面的文字均來自其它博客和網頁。
參考:http://www.jianshu.com/p/ea9a482ece5f
由于同一進程的多個線程共享同一片存儲空間,在帶來方便的同時,也帶來了訪問沖突這個嚴重的問題。Java語言提供了專門機制以解決這種沖突,有效避免了同一個數據對象被多個線程同時訪問。
需要明確的幾個問題:
- synchronized關鍵字可以作為函數的修飾符,也可作為函數內的語句,也就是平時說的同步方法和同步語句塊。如果 再細的分類,synchronized可作用于instance變量、object reference(對象引用)、static函數和class literals(類名稱字面常量)身上。
- 無論synchronized關鍵字加在方法上還是對象上,它取得的鎖都是對象,而不是把一段代碼或函數當作鎖――而且同步方法很可能還會被其他線程的對象訪問。
- 每個對象只有一個鎖(lock)與之相關聯。
- 實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。
synchronized關鍵字的作用域有二種:
synchronized 方法
每個類實例對應一把鎖,每個 synchronized 方法都必須獲得調用該方法的類實例的鎖方能執行,否則所屬線程阻塞,方法一旦執行,就獨占該鎖,直到從該方法返回時才將鎖釋放,此后被阻塞的線程方能獲得該鎖,重新進入可執行狀態。這種機制確保了同一時刻對于每一個類實例,其所有聲明為 synchronized 的成員函數中至多只有一個處于可執行狀態(因為至多只有一個能夠獲得該類實例對應的鎖),從而有效避免了類成員變量的訪問沖突(只要所有可能訪問類成員變量的方法均被聲明為 synchronized)。
在 Java 中,不光是類實例,每一個類也對應一把鎖,這樣我們也可將類的靜態成員函數聲明為 synchronized ,以控制其對類的靜態成員變量的訪問。
synchronized 方法的缺陷
同步方法,這時synchronized鎖定的是哪個對象呢?它鎖定的是調用這個同步方法對象。也就是說,當一個對象 P1在不同的線程中執行這個同步方法時,它們之間會形成互斥,達到同步的效果。但是這個對象所屬的Class所產生的另一對象P2卻可以任意調用這個被加 了synchronized關鍵字的方法.同步方法實質是將synchronized作用于object reference。――那個拿到了P1對象鎖的線程,才可以調用P1的同步方法,而對P2而言,P1這個鎖與它毫不相干,程序也可能在這種情形下擺脫同步機制的控制,造成數據混亂:(
;若將一個大的方法聲明為synchronized 將會大大影響效率,典型地,若將線程類的方法 run() 聲明為 synchronized ,由于在線程的整個生命期內它一直在運行,因此將導致它對本類任何 synchronized 方法的調用都永遠不會成功。當然我們可以通過將訪問類成員變量的代碼放到專門的方法中,將其聲明為 synchronized ,并在主方法中調用來解決這一問題,但是 Java 為我們提供了更好的解決辦法,那就是 synchronized 塊。
synchronized 代碼塊
除了方法前用synchronized關鍵字,synchronized關鍵字還可以用于方法中的某個區塊中,表示只對這個區塊的資源實行互斥訪問。用法是: synchronized(this){/區塊/},它的作用域是當前對象。
這時鎖就是對象,誰拿到這個鎖誰就可以運行它所控制的那段代碼。當有一個明確的對象作為鎖時,就可以這樣寫程序,但當沒有明確的對象作為鎖,只是想讓一段代碼同步時,可以創建一個特殊的instance變量(它得是一個對象)來充當鎖:
注:零長度的byte數組對象創建起來將比任何對象都經濟――查看編譯后的字節碼:生成零長度的byte[]對象只需3條操作碼,而Object lock = new Object()則需要7行操作碼。
synchronized 靜態方法
將synchronized作用于static 函數,示例代碼如下:
Class Foo {// 同步的static 函數public synchronized static void methodAAA() {//….}public void methodBBB() {synchronized(Foo.class) // class literal(類名稱字面常量)} }代碼中的methodBBB()方法是把class literal作為鎖的情況,它和同步的static函數產生的效果是一樣的,取得的鎖很特別,是當前調用這個方法的對象所屬的類(Class,而不再是由這個Class產生的某個具體對象了)。
可以推斷:如果一個類中定義了一個synchronized 的 static 函數A,也定義了一個 synchronized 的 instance函數B,那么這個類的同一對象Obj在多線程中分別訪問A和B兩個方法時,不會構成同步,因為它們的鎖都不一樣。B方法的鎖是Obj這個對象,而B的鎖是Obj所屬的那個Class。
?
文/DanieX(簡書作者)
原文鏈接:http://www.jianshu.com/p/ea9a482ece5f
著作權歸作者所有,轉載請聯系作者獲得授權,并標注“簡書作者”。
下面是另一篇博客,寫得也不錯。
來自: http://zhangjunhd.blog.51cto.com/113473/70300/
在并發環境下,解決共享資源沖突問題時,可以考慮使用鎖機制。
1.對象的鎖
所有對象都自動含有單一的鎖。
JVM負責跟蹤對象被加鎖的次數。如果一個對象被解鎖,其計數變為0。在任務(線程)第一次給對象加鎖的時候,計數變為1。每當這個相同的任務(線程)在此對象上獲得鎖時,計數會遞增。
只有首先獲得鎖的任務(線程)才能繼續獲取該對象上的多個鎖。
每當任務離開一個synchronized方法,計數遞減,當計數為0的時候,鎖被完全釋放,此時別的任務就可以使用此資源。
2.synchronized同步塊
2.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()
2.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()
3.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()
?
from:?https://www.cnblogs.com/beiyetengqing/p/6213437.html
總結
以上是生活随笔為你收集整理的Java synchronized 详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 让你彻底理解Synchronized
- 下一篇: Java并发编程 Synchronize