生活随笔
收集整理的這篇文章主要介紹了
Java线程同步:synchronized锁住的是代码还是对象
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在Java中,synchronized關鍵字是用來控制線程同步的,就是在多線程的環境下,控制synchronized代碼段不被多個線程同時執行。synchronized既可以加在一段代碼上,也可以加在方法上。
關鍵是,不要認為給方法或者代碼段加上synchronized就萬事大吉,看下面一段代碼:
[java]?view plaincopy
class?Sync?{?? ?? ????public?synchronized?void?test()?{?? ????????System.out.println("test開始..");?? ????????try?{?? ????????????Thread.sleep(1000);?? ????????}?catch?(InterruptedException?e)?{?? ????????????e.printStackTrace();?? ????????}?? ????????System.out.println("test結束..");?? ????}?? }?? ?? class?MyThread?extends?Thread?{?? ?? ????public?void?run()?{?? ????????Sync?sync?=?new?Sync();?? ????????sync.test();?? ????}?? }?? ?? public?class?Main?{?? ?? ????public?static?void?main(String[]?args)?{?? ????????for?(int?i?=?0;?i?<?3;?i++)?{?? ????????????Thread?thread?=?new?MyThread();?? ????????????thread.start();?? ????????}?? ????}?? }??
運行結果:
test開始..
test開始..
test開始..
test結束..
test結束..
test結束..
可以看出來,上面的程序起了三個線程,同時運行Sync類中的test()方法,雖然test()方法加上了synchronized,但是還是同時運行起來,貌似synchronized沒起作用。?
將test()方法上的synchronized去掉,在方法內部加上synchronized(this):
[java]?view plaincopy
public?void?test()?{?? ????synchronized(this){?? ????????System.out.println("test開始..");?? ????????try?{?? ????????????Thread.sleep(1000);?? ????????}?catch?(InterruptedException?e)?{?? ????????????e.printStackTrace();?? ????????}?? ????????System.out.println("test結束..");?? ????}?? }??
運行結果:
test開始..
test開始..
test開始..
test結束..
test結束..
test結束..
一切還是這么平靜,沒有看到synchronized起到作用。?
實際上,synchronized(this)以及非static的synchronized方法(至于static synchronized方法請往下看),只能防止多個線程同時執行同一個對象的同步代碼段。
回到本文的題目上:synchronized鎖住的是代碼還是對象。答案是:synchronized鎖住的是括號里的對象,而不是代碼。對于非static的synchronized方法,鎖的就是對象本身也就是this。
當synchronized鎖住一個對象后,別的線程如果也想拿到這個對象的鎖,就必須等待這個線程執行完成釋放鎖,才能再次給對象加鎖,這樣才達到線程同步的目的。即使兩個不同的代碼段,都要鎖同一個對象,那么這兩個代碼段也不能在多線程環境下同時運行。
所以我們在用synchronized關鍵字的時候,能縮小代碼段的范圍就盡量縮小,能在代碼段上加同步就不要再整個方法上加同步。這叫減小鎖的粒度,使代碼更大程度的并發。原因是基于以上的思想,鎖的代碼段太長了,別的線程是不是要等很久,等的花兒都謝了。當然這段是題外話,與本文核心思想并無太大關聯。
再看上面的代碼,每個線程中都new了一個Sync類的對象,也就是產生了三個Sync對象,由于不是同一個對象,所以可以多線程同時運行synchronized方法或代碼段。
為了驗證上述的觀點,修改一下代碼,讓三個線程使用同一個Sync的對象。
[java]?view plaincopy
class?MyThread?extends?Thread?{?? ?? ????private?Sync?sync;?? ?? ????public?MyThread(Sync?sync)?{?? ????????this.sync?=?sync;?? ????}?? ?? ????public?void?run()?{?? ????????sync.test();?? ????}?? }?? ?? public?class?Main?{?? ?? ????public?static?void?main(String[]?args)?{?? ????????Sync?sync?=?new?Sync();?? ????????for?(int?i?=?0;?i?<?3;?i++)?{?? ????????????Thread?thread?=?new?MyThread(sync);?? ????????????thread.start();?? ????????}?? ????}?? }??
運行結果:
test開始..
test結束..
test開始..
test結束..
test開始..
test結束..
可以看到,此時的synchronized就起了作用。?
那么,如果真的想鎖住這段代碼,要怎么做?也就是,如果還是最開始的那段代碼,每個線程new一個Sync對象,怎么才能讓test方法不會被多線程執行。?
解決也很簡單,只要鎖住同一個對象不就行了。例如,synchronized后的括號中鎖同一個固定對象,這樣就行了。這樣是沒問題,但是,比較多的做法是讓synchronized鎖這個類對應的Class對象。
[java]?view plaincopy
class?Sync?{?? ?? ????public?void?test()?{?? ????????synchronized?(Sync.class)?{?? ????????????System.out.println("test開始..");?? ????????????try?{?? ????????????????Thread.sleep(1000);?? ????????????}?catch?(InterruptedException?e)?{?? ????????????????e.printStackTrace();?? ????????????}?? ????????????System.out.println("test結束..");?? ????????}?? ????}?? }?? ?? class?MyThread?extends?Thread?{?? ?? ????public?void?run()?{?? ????????Sync?sync?=?new?Sync();?? ????????sync.test();?? ????}?? }?? ?? public?class?Main?{?? ?? ????public?static?void?main(String[]?args)?{?? ????????for?(int?i?=?0;?i?<?3;?i++)?{?? ????????????Thread?thread?=?new?MyThread();?? ????????????thread.start();?? ????????}?? ????}?? }??
運行結果:
test開始..
test結束..
test開始..
test結束..
test開始..
test結束..
上面代碼用synchronized(Sync.class)實現了全局鎖的效果。
最后說說static synchronized方法,static方法可以直接類名加方法名調用,方法中無法使用this,所以它鎖的不是this,而是類的Class對象,所以,static synchronized方法也相當于全局鎖,相當于鎖住了代碼段。
?
作者:叉叉哥?? 轉載請注明出處:http://blog.csdn.net/xiao__gui/article/details/8188833?
總結
以上是生活随笔為你收集整理的Java线程同步:synchronized锁住的是代码还是对象的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。