簡體   English   中英

使類線程安全

[英]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執行該方法的前體。 但是,由於xstatic ,因此無法確保對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對象的鎖定。

由於xstatic其他線程可以在運行doThings方法的同時修改它。 使doThings static將阻止這一點。

我同意你的正確答案是D.我會說E是不正確的,因為如果我將doThings()設置為靜態並刪除synchronized關鍵字,我可以啟動50個TestSeven線程,它可能導致不正確的x值。

注意:我在這里錯了,我錯過了沒有靜態的synchronized方法實際上使用實例作為鎖定監視器而不是類本身。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM