[英]Making a class Thread-Safe
鑒於:
public class TestSeven extends Thread {
private static int x;
public synchronized void doThings() {
int current = x;
current++;
x = current;
}
public void run() {
doThings();
}
}
哪個論述是對的?
A.編譯失敗。
B.在運行時拋出異常。
C.同步run()方法會使類成為線程安全的。
D.變量“x”中的數據受到保護,不會出現並發訪問問題。
E.將doThings()方法聲明為static將使類成為線程安全的。
F.在同步(new Object()){}塊中包裝doThings()中的語句將使該類成為線程安全的。
是不是足以將doThings()標記為已同步以使該類具有線程安全性? 我看到正確答案是D但這個問題的模型答案是E,但我不明白為什么?
E.將doThings()方法聲明為static將使類成為線程安全的。
這是一個棘手的答案。 該方法已經同步,但在實例上,而狀態是在靜態字段中,即在類上。 使它static synchronized
確實是正確的答案,因為它在類上同步,而不是在(無意義的)實例上同步。
D.變量“x”中的數據受到保護,不會出現並發訪問問題。
private static int x;
這是一個靜態變量。 它由類的所有實例共享,因此在單個實例上進行同步是沒有用的,就像F沒有幫助的方式一樣,它在完全丟棄的虛擬對象上同步。
根據語言規范 :
同步方法在執行之前獲取監視器(第17.1節)。
對於類(靜態)方法,使用與方法類的Class對象關聯的監視器。
對於實例方法,使用與此關聯的監視器(調用該方法的對象)。
這意味着,在該代碼時所提供的synchronized
關鍵字使獲得的鎖的方法this
執行該方法的前體。 但是,由於x
是static
,因此無法確保對x
的更新是原子的。 (該類的另一個實例可以進入同步區域並同時進行更新,因為它們具有不同的this
值,因此具有不同的鎖定。)
但是,聲明doStuff
static會使對方法的所有調用都獲得相同的鎖( Class
上的那個),從而確保方法體中的互斥。
規范確實說明:
class A {
static synchronized void doSomething() {
// ...
}
}
與字面意思完全相同
class A {
static void doSomething() {
synchronized(A.class) {
// ...
}
}
}
同理:
class B {
synchronized void doSomething() {
// ...
}
}
與字面意思完全相同
class B {
void doSomething() {
synchronized (this) {
// ...
}
}
}
通過同步doThings()方法,您將持有特定TestSeven對象的鎖。 但是,類的靜態變量不屬於對象本身的特定實例。 它們屬於Class對象TestSeven.class
。 所以,要么你可以去找一個
synchronized (TestSeven.class){
int current = x;
current++;
x = current;
}
在你的doThings()方法中,它正在一個實例鎖中獲取類鎖,這是一個過度的東西。 因此,您可以將方法標記為靜態,以便最終單獨獲取Class對象的鎖定。
由於x
是static
其他線程可以在運行doThings
方法的同時修改它。 使doThings
static
將阻止這一點。
我同意你的正確答案是D.我會說E是不正確的,因為如果我將doThings()設置為靜態並刪除synchronized關鍵字,我可以啟動50個TestSeven線程,它可能導致不正確的x值。
注意:我在這里錯了,我錯過了沒有靜態的synchronized方法實際上使用實例作為鎖定監視器而不是類本身。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.