最近重新梳理了下java的synchronized相關內容,希望能幫助到有需要的朋友們。
主要闡述以下幾個問題:
1.非static方法前加synchronized
class Demo{
synchronized public void doXXX(){
//code…
}
}
對於這段代碼,我們要考慮這幾個問題:
- 理解synchronized鎖的是什麼?
- 如果三個線程裏分別new了三個Demo對象,各自的run方法裏分別執行各自Demo對象的doXXX方法,那麼synchronized還起作用嗎?
- 如果三個線程裏共用一個Demo對象,各自的run方法裏分別執行這個共用Demo對象的doXXX方法,那麼synchronized還起作用嗎?
在非static方法前面加synchronized,鎖的是這個new出來的Demo對象的本身,也就是this。要執行doXXX方法,必須要先獲取對象鎖(即對象本身)。
所以,2中doXXX的對象鎖來自3個不同的Demo對象,各自線程使用各自Demo對象的鎖,不存在共用鎖的情況,synchronized不起作用。
同理,3中doXXX的對象鎖來自1個相同的Demo對象,各自線程使用同個Demo對象的鎖,存在共用鎖的情況,synchronized起作用。
2.方法內部synchronized同步塊
class Demo {
public void doXXX(){
synchronized(this){
//code…
}
}
}
對於這段代碼,我們需要考慮這幾個問題:
- 括號裏填this?
- 括號裏填類.class?
- 括號裏填一個對象?
synchronized鎖住的是括號裏的對象,而不是代碼。所以多線程情況下要執行doXXX,要先獲得鎖,即括號裏指定的內容。
分析:
- 如果填this,多線程共用同一個Demo對象時,可以控制併發操作帶來的問題,如果各個線程使用各自的Demo對象時,是沒有用的。
- 如果填類.class,相當於對類加鎖,也就是在該類的所有成員間實現互斥,在同一時間只有一個線程可訪問該類的實例(如果需要在線程間相互喚醒就需要藉助Object類的wait()方法及nofity()方法),這種方法,不管各個線程使用同一個Demo對象還是使用各自的Demo對象,都可以解決併發操作帶來的問題。一般用方法所在類.class或者方法所在類內部定義一個static的對象,作爲鎖。這種方式稱爲全局鎖。
- 對象的情況有很多,可以來自Demo類內部(static和非static),外部傳入(static和非static),但是要傳哪種,相信你看完上面兩條分析,心裏應該有數了。
3.static方法前加synchronized
class Demo{
public static synchronized void doXXX{
//code…
}
}
static的synchronized方法,所以它鎖的不是this,而是類的Class對象,而且方法中無法使用this。可見,這種方式不管new幾個Deom調用doXXX,都不會併發。
相信你理解了上面三個問題,那麼你對synchronized關鍵字就有了一定的瞭解,並能夠將它運用在處理併發操作的問題上了。
-----------------------------------------------------
請尊重作者勞動成果,
轉載請註明出處