-1

this java tutorial中有一些代碼顯示了一個示例來說明​​關鍵字的使用。我的觀點是,爲什麼我不應該寫的是這樣的:關於synchronized關鍵字如何處理鎖定和線程匱乏的問題

public class MsLunch { 
    private long c1 = 0; 
    private long c2 = 0; 
    //private Object lock1 = new Object(); 
    //private Object lock2 = new Object(); 

    public void inc1() { 
     synchronized(c1) { 
      c1++; 
     } 
    } 

    public void inc2() { 
     synchronized(c2) { 
      c2++; 
     } 
    } 
} 

,而不會打擾創建鎖定的對象?另外,爲什麼麻煩實例化那個鎖定對象?我不能只傳遞一個空引用?我想我在這裏錯過了一些東西。

另外,假設我有兩個公共同步方法在同一個類中被多個線程訪問。這兩種方法永遠不會同時執行是真的嗎?如果答案是肯定的,是否有一種內置的機制可以防止一種方法捱餓(從未執行過或執行過的次數與其他方法相比)?

+0

爲什麼反對票?我應該把這個問題提交給程序員嗎? – JoulinRouge

+1

您只能同步對象。在null上同步將拋出一個NPE。 – shmosel

回答

3

首先,您不能將原始變量傳遞給​​,它需要引用。其次,教程只是一個示例,顯示了防護區塊。它不是c1,c2,它試圖保護,但它試圖保護​​區塊內的所有代碼。

JVM使用操作系統的調度算法。

What is the JVM Scheduling algorithm?

所以它不是JVM的責任,看看是否線程餓死。但是,您可以分配線程的優先級,使其優先於其他線程執行。

每個線程都有一個優先級。優先級較高的線程優先於較低優先級的線程執行。每個線程可能也可能不會被標記爲守護進程。當在某個線程中運行的代碼創建一個新的Thread對象時,新線程的優先級初始設置等於創建線程的優先級,並且當且僅當創建線程是守護進程時纔是守護線程。

來源:https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html

如果你很在意這種情況下,你必須自己實現它。就像維護一個線程一樣,它會檢查飢餓的線程,並且隨着時間的推移它會增加等待時間比其他線程更長的線程的優先級。

是的,確實兩個已同步的方法永遠不會同時在同一個實例上執行。

+0

假定同步對同一個對象起作用是正確的,它提供的監視器不是不同的對象。 – 11thdimension

3

由於@ 11thdimension已回覆,您不能在原始類型(例如,長)上同步。它必須是一個類對象。

所以,你可能會做一些類似如下:

Long c1 = 0; 
public void incC1() { 
    synchronized(c1) { 
    c1++; 
    } 
} 

這將無法正常工作,爲「C1 ++」是「C1 = C1 + 1」,這實際上分配一個快捷方式新對象c1,因此,兩個線程可能會在同一個代碼塊中結束。

爲使鎖正常工作,不應重新分配正在同步的對象。 (好吧,也許在一些你很清楚自己在幹什麼的情況下)。

你不能將空對象傳遞給synchronized(...)聲明。 Java在ref'd對象上有效地創建信號量,並使用該信息阻止多個線程訪問相同的受保護資源。

您並不總是需要單獨的鎖定對象,如同步方法的情況。在這種情況下,類對象實例本身是用來存儲鎖定信息,因爲如果你的方法iteslf用「這個」:

public void incC1() { 
    synchronized(this) { 
     c1++; 
    } 
} 
+0

謝謝!你能否提供一個「Java是否有效地在ref'd對象上創建信號量」的源代碼? – JoulinRouge

+0

看來'信號量'不是很合適的詞,而是'監視器鎖'或'內部鎖'。 https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html – Jamie

1

何苦實例化對象的鎖?我不能只傳遞一個空引用?

正如其他人所說,你不能鎖定long c1,因爲它是一個原始的。與對象實例關聯的監視器上的Java鎖定。這就是爲什麼你也無法鎖定null

thread tutorial正試圖展示一個很好的模式,即創建private final鎖對象以精確控制您嘗試保護的互斥鎖位置。撥打​​this或其他public對象可能導致外部呼叫者阻止您的方法,可能不是你想要的。

的教程解釋這一點:

這些領域的所有更新必須是同步的,但沒有理由阻止C1的更新被交錯與C2的更新 - 而這樣做創建降低併發不必要的阻塞我們不使用同步方法或使用與此相關的鎖,而是創建兩個對象來提供鎖。

因此,他們也試圖允許更新c1和更新c2到同時發生(「交錯」),並同時在同一時間,確保將這些更新保護不能阻止對方。

假設我在同一個類中有兩個公共同步方法被多個線程訪問。這兩種方法永遠不會同時執行是真的嗎?

如果一個線程在對象的​​方法工作,另一個線程將被如果它試圖相同或同一對象的另一​​方法阻塞。線程可以同時運行不同的對象上的方法。

如果答案是肯定的,有沒有阻止一個方法從飢餓內置機制(從未被執行或者被執行過幾次相比於其他方法)?

如前所述,這是由操作系統的本地線程結構處理的。所有現代OS都處理線程匱乏,如果線程具有不同的優先級,這尤其重要。