線程安全是編程中的術(shù)語(yǔ),指某個(gè)函數(shù) (計(jì)算機(jī)科學(xué))、函數(shù)庫(kù)在多線程環(huán)境中被調(diào)用時(shí),能夠正確地處理各個(gè)線程的局部變量,使程序功能正確完成。這是維基百科里的資料,看完后還不是特別的明白。我自己的理解就是在多線程環(huán)境下,某塊代碼中訪問(wèn)的資源不會(huì)發(fā)生沖突。寫(xiě)這篇筆記的起因是上周的支付寶電話面試中問(wèn)了我一個(gè)線程安全的問(wèn)題,就是有一個(gè)類(lèi),他的方法A是加了synchronized關(guān)鍵字的,然后分別創(chuàng)建這個(gè)類(lèi)的兩個(gè)實(shí)例,請(qǐng)問(wèn),當(dāng)多個(gè)線程同時(shí)訪問(wèn)這兩個(gè)實(shí)例中的方法A時(shí)synchronized會(huì)起作用嗎?當(dāng)時(shí)我的回答還是很明確而自信的說(shuō)“會(huì)”,今天覺(jué)得這個(gè)問(wèn)題要好好研究一下,于是就寫(xiě)了代碼做了一下測(cè)試,發(fā)現(xiàn)自己答錯(cuò)了,這或許是我面試失敗的原因之一吧。代碼貼出來(lái):
class Thread2 extends Thread{ public void run() { MyObj obj = new MyObj(); try { obj.sayHello(3000);//3秒 } catch (InterruptedException e) { e.PRintStackTrace(); } }}class Thread3 extends Thread{ public void run() { MyObj obj = new MyObj(); try { obj.sayHello(1000);//1秒 } catch (InterruptedException e) { e.printStackTrace(); } }}class MyObj { public synchronized void sayHello(int delay) throws InterruptedException{ Thread.sleep(delay); System.out.println("delay" + delay); }}public class ThreadTest { public static void main(String[] args) throws Exception{ Thread2 t2 = new Thread2(); Thread3 t3 = new Thread3(); t2.start();//先讓t2線程啟動(dòng),因?yàn)閠2要等待3秒,如果線程同步有作用的話t3會(huì)處理阻塞狀態(tài) t3.start(); }}代碼中的MyObj類(lèi)就是我用于測(cè)試的線程安全的對(duì)象,它包含了一個(gè)sayHello方法,他是帶有synchronized關(guān)鍵字的。但測(cè)試結(jié)果卻是
delay1000delay3000
這說(shuō)明關(guān)鍵字沒(méi)有起作用,也說(shuō)明了不同的對(duì)象實(shí)例synchronized方法時(shí)是線程不安全的。知道這個(gè)結(jié)果心里有些難過(guò),只不過(guò)事情已經(jīng)過(guò)去就當(dāng)是學(xué)習(xí)了經(jīng)驗(yàn)吧。
synchronized除了修飾方法外,還可以修飾代碼塊,那就試試看吧,寫(xiě)了一個(gè)新的類(lèi):
class MyObj2 { private static Object lockObj = new Object(); public void sayHello(int delay) throws InterruptedException{ synchronized(lockObj){ Thread.sleep(delay); System.out.println("delay" + delay); } }}用這個(gè)類(lèi)做測(cè)試的結(jié)果:
delay3000delay1000
這說(shuō)明synchronized修改代碼塊時(shí)線程同步是起作用的,但這里要注意,采用synchronized代碼塊時(shí),synchronized(lockObj)中的lockObj對(duì)象是一個(gè)靜態(tài)對(duì)象,所以他們對(duì)應(yīng)的鎖是同一個(gè),這就可以實(shí)現(xiàn)線程間的同步。如果換成synchronized(this)又無(wú)法同步。
于是就得想明白為什么會(huì)有這兩種差別呢?原來(lái)JAVA中每個(gè)對(duì)象都對(duì)應(yīng)一個(gè)鎖,synchronized關(guān)鍵字是通過(guò)檢查這個(gè)對(duì)象鎖的狀態(tài)來(lái)調(diào)度的。這下就明白了,原來(lái)關(guān)鍵就在于對(duì)象對(duì)應(yīng)的那個(gè)鎖,MyObj之所以不能同步是因?yàn)閯?chuàng)建了兩不同的對(duì)象實(shí)例,自然對(duì)應(yīng)的對(duì)象鎖就不同,而synchronized修飾的是方法時(shí),其對(duì)應(yīng)檢查的是當(dāng)前對(duì)象的鎖,所以就會(huì)出現(xiàn)不同步的情況。
后來(lái)在網(wǎng)上查資料的同時(shí)也發(fā)現(xiàn)一個(gè)叫類(lèi)鎖的東東,通過(guò)類(lèi)鎖獲得的類(lèi)本身,是唯一的,那么就應(yīng)該是可以同步了,代碼如下:
class MyObj3 { public synchronized static void sayHello(int delay) throws InterruptedException{ Thread.sleep(delay); System.out.println("delay" + delay); }}得到的結(jié)果
delay3000delay1000
這說(shuō)明已經(jīng)同步了,synchronized+static一起修改時(shí)獲得的是類(lèi)鎖,獲得類(lèi)本身,所以只有一個(gè),那么同步自然有了效果。
注:“光之子”在評(píng)論中指出了本文的一些問(wèn)題,有興趣的朋友看到本文請(qǐng)把評(píng)論也看看吧。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注