? ? ? ? 造成線程安全問題的原因有兩個松蒜?線程數(shù)據(jù)共享。多線程同時操作共享數(shù)據(jù)已旧。在JAVA中Synchronized可以保證統(tǒng)一時刻秸苗,只有一個線程執(zhí)行某個方法或者執(zhí)行某個代碼塊;Synchronized可以保證數(shù)據(jù)的可見性运褪。Synchronizeds是互斥鎖惊楼。
一、Synchronized的三種使用方式
1秸讹、修飾實例方法檀咙,作用于當前實例加鎖,進入同步代碼前要獲得當前實例鎖璃诀。
2弧可、修飾靜態(tài)方法,作用于當前類對象鎖文虏,進入同步代碼前要獲取當前類對象鎖侣诺。
3殖演、修飾代碼塊,指定加鎖對象年鸳,對給定對象加鎖趴久,進入同步代碼塊前要獲得給定對象的鎖。
1.1 Synchronized 作用于實例方法
????????此時我們應(yīng)該注意到synchronized修飾的是實例方法add搔确,在這樣的情況下彼棍,當前線程的鎖便是實例對象instance,注意Java中的線程同步鎖可以是任意對象膳算。當一個線程正在訪問一個對象的synchronized方法座硕,其他線程必須等待該線程結(jié)束,才能獲取到訪問權(quán)限涕蜂。
? ? ? ? 如果線程 ThreadA 訪問實例對象 ObjectA的 synchronized 方法 add华匾。另一個線程 ThreadB 需要訪問實例對象 ObjectB 的 synchronized 方法 add,因為兩個實例對象鎖并不同相同机隙,所有可用同時訪問蜘拉。此時如果兩個線程訪問了共享變量,那么會出現(xiàn)數(shù)據(jù)不一致的情況有鹿。如下程序旭旭,雖然有同步方法,但是還是會出現(xiàn)不一致情況葱跋。
如圖1中的類main方法改如下:
public static void main(String [] args) throws InterruptedException {
? ? ?SynchronizedClass instance = new SynchronizedClass();
? ? ?SynchronizedClass instance1 = new SynchronizedClass();
? ? ?Thread t1 = new Thread(instance);?
? ? ?Thread t2 = new Thread(instance1);?
? ? ? t1.start(); t2.start(); t1.join(); t2.join();?
? ? ? System.out.println(i);??
}
1.2 Synchronized 作用于靜態(tài)方法
? ? ? ? 一個線程A調(diào)用一個實例對象的非static synchronized方法持寄,而線程B需要調(diào)用這個實例對象所屬類的靜態(tài) synchronized方法,是允許的娱俺,不會發(fā)生互斥現(xiàn)象稍味。因為訪問靜態(tài) synchronized 方法占用的鎖是當前類的class對象,而訪問非靜態(tài) synchronized 方法占用的鎖是當前實例對象鎖荠卷。static synchronized所有對象之間是互斥的仲闽。
1.3 Synchronized 同步代碼塊
代碼同步塊,synchronized在某個方法內(nèi)的代碼塊上僵朗;synchronized作用的對象是一個今天對象。這樣可以保證在靜態(tài)同步塊屑彻。
二验庙、可重入鎖
如下代碼塊,調(diào)用方法methodB時社牲,獲得了鎖粪薛,在執(zhí)行methodB時,調(diào)用方法methodA時搏恤,methodA也有代碼塊违寿,所有會自動會methodA的鎖湃交。這就是可重入鎖。
public synchronized methodA(){
? ? System.out.println("methodA");
}
public void methodB(){
? ? sychronized(this){
? ? ? ? System.out.println("methodB");
? ? ? ? methodA()
????}
}
三藤巢、線程中斷和喚醒
? ? ? ? 等待喚醒指的是notify/notifyAll和wait方法搞莺,在使用這3個方法時,必須處于synchronized代碼塊或者synchronized方法中掂咒,否則就會拋出IllegalMonitorStateException異常才沧,這是因為調(diào)用這幾個方法前必須拿到當前對象的監(jiān)視器monitor對象,也就是說notify/notifyAll和wait方法依賴于monitor對象绍刮,monitor 存在于對象頭的Mark Word 中(存儲monitor引用指針)温圆,而synchronized關(guān)鍵字可以獲取 monitor ,這也就是為什么notify/notifyAll和wait方法必須在synchronized代碼塊或者synchronized方法調(diào)用的原因孩革。
? ? ? ?wait方法將會釋放當前持有的監(jiān)視器鎖(monitor)岁歉,直到有線程調(diào)用notify/notifyAll方法后方能繼續(xù)執(zhí)行;而sleep方法只讓線程休眠并不釋放鎖膝蜈。
? ? ? ? 同時notify/notifyAll方法調(diào)用后锅移,并不會馬上釋放監(jiān)視器鎖,而是在相應(yīng)的synchronized(){}/synchronized方法執(zhí)行結(jié)束后才自動釋放鎖彬檀。
參考
http://www.reibang.com/p/7ddb0956590c