?面試題:
答案:
不能
不能
不能
不能
能
正文
概述
通過分析這兩個用法的分析,我們可以理解java中鎖的概念,一個是實體鎖(鎖在某一個實體物件上,如果該類是單例,那么該鎖也具有全域鎖的概念),一個是全域鎖(該鎖針對的是類,無論實體多少個物件,那么執行緒都共享該鎖),實體鎖對應的就是synchronized關鍵字,而類鎖(全域鎖)對應的就是static synchronized(或者是鎖在該類的class或者classloader物件上),
區別
synchronized關鍵字
synchronized作用是對類的當前實體(物件)加鎖,可以使用synchronized關鍵字來標記一個方法或者代碼塊,當某個執行緒呼叫該物件的synchronized方法或者訪問synchronized代碼塊時,這個執行緒便獲得了該物件的鎖,其他執行緒暫時無法訪問這個方法,只有等待這個方法執行完畢或者代碼塊執行完畢,這個執行緒才會釋放該物件的鎖(Java 并發編程),
synchronized代碼塊【synchronized(synObject)】使用起來比synchronized方法要靈活得多,因為也許一個方法中只有一部分代碼只需要同步,如果此時對整個方法用synchronized進行同步,會影響程式執行效率,而使用synchronized代碼塊就可以避免這個問題(同步物件或類屬性),synchronized代碼塊可以實作只對需要同步的地方進行同步,
與Lock的區別:1. synchronized是Java語言的關鍵字,因此是內置特性,Lock是一個類(java.util.concurrent.locks包),通過這個類可以實作同步訪問;2. synchronized不需要用戶去手動釋放鎖,當synchronized方法或者synchronized代碼塊執行完之后,系統會自動讓執行緒釋放對鎖的占用,Lock則必須要用戶去手動釋放鎖,如果沒有主動釋放鎖,就有可能導致出現死鎖現象,
static synchronized:
每個類有一個鎖,它可以用來控制對static資料成員的并發訪問,訪問static synchronized方法占用的是類鎖,而訪問非static synchronized方法占用的是物件鎖,
static synchronized控制類的所有實體(物件)的訪問(相應代碼塊),synchronized相當于 this.synchronized,static synchronized相當于Something.synchronized
一個日本作者-結成浩的《java多執行緒設計模式》有這樣的一個列子:
pulbic class Something(){
public synchronized void isSyncA(){}
public synchronized void isSyncB(){}
public static synchronized void cSyncA(){}
public static synchronized void cSyncB(){}
}
那么,假如有Something類的兩個實體x與y,那么下列各組方法被多執行緒同時訪問的情況是怎樣的?
a. x.isSyncA()與x.isSyncB()
b. x.isSyncA()與y.isSyncA()
c. x.cSyncA()與y.cSyncB()
d. x.isSyncA()與Something.cSyncA()
這里,很清楚的可以判斷:
-
都是對同一個實體(x)的synchronized域訪問,因此不能被同時訪問,(多執行緒中訪問x的不同synchronized域不能同時訪問)
如果在多個執行緒中訪問x.isSyncA(),因為仍然是對同一個實體,且對同一個方法加鎖,所以多個執行緒中也不能同時訪問,(多執行緒中訪問x的同一個synchronized域不能同時訪問)
-
是針對不同實體的,因此可以同時被訪問(物件鎖對于不同的物件實體沒有鎖的約束)
-
因為是static synchronized,所以不同實體之間仍然會被限制,相當于Something.isSyncA()與 Something.isSyncB()了,因此不能被同時訪問,
-
書上的 答案是可以被同時訪問的,答案理由是synchronzied的是實體方法與synchronzied的類方法由于鎖定(lock)不同的原因,
個人分析也就是synchronized 與static synchronized 相當于兩幫派,各自管各自,相互之間就無約束了,可以被同時訪問,
舉個例子:
public class TestSynchronized { public synchronized void test1() { int i = 5; while (i-- > 0) { System.out.println(Thread.currentThread().getName() + " : " + i); try { Thread.sleep(500); } catch (InterruptedException ie) { } } } public static synchronized void test2() { int i = 5; while (i-- > 0) { System.out.println(Thread.currentThread().getName() + " : " + i); try { Thread.sleep(500); } catch (InterruptedException ie) { } } } public static void main(String[] args) { final TestSynchronized myt2 = new TestSynchronized(); Thread test1 = new Thread(new Runnable() { public void run() { myt2.test1(); } }, "test1"); Thread test2 = new Thread(new Runnable() { public void run() { TestSynchronized.test2(); } }, "test2"); test1.start(); test2.start(); } }
test1 : 4 test2 : 4 test1 : 3 test2 : 3 test2 : 2 test1 : 2 test2 : 1 test1 : 1 test1 : 0 test2 : 0
上面代碼synchronized同時修飾靜態方法和實體方法,但是運行結果是交替進行的,這證明了類鎖和物件鎖是兩個不一樣的鎖,控制著不同的區域,它們是互不干擾的,同樣,執行緒獲得物件鎖的同時,也可以獲得該類鎖,即同時獲得兩個鎖,這是允許的,
結論
A: synchronized static是某個類的范圍,synchronized static cSync{}防止多個執行緒中多個實體同時訪問這個 類中的synchronized static 方法,它可以對類的所有物件實體起作用,
B: synchronized 是某實體的范圍,synchronized isSync(){}防止多個執行緒中這一個實體同時訪問這個類的synchronized 方法,
其實總結起來很簡單,
-
一個鎖的是類物件,一個鎖的是實體物件,
-
若類物件被lock,則類物件的所有同步方法全被lock;
-
若實體物件被lock,則該實體物件的所有同步方法全被lock,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/5230.html
標籤:其他
上一篇:【計算機網路】UDP基礎知識總結
下一篇:GC與記憶體分配策略
