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