2011-03-16 76 views
0

假設我有一個靜態變量,它是一個大小爲5的數組。 假設我有兩個線程T1和T2,它們都嘗試更改該數組的索引0處的元素。然後使用索引爲0的元素。 在這種情況下,我應該鎖定數組,直到T1完成使用元素的權利?靜態數組變量需要被鎖定?

另一個問題是讓我們說T1和T2已經在運行,首先在索引0的T1訪問元素,然後鎖定它。但是在T2嘗試訪問索引0處的元素之後,但是T1尚未解鎖索引0。那麼在這種情況下,爲了使T2訪問索引0處的元素,T2應該做什麼?在T1解鎖數組的索引0之後,T2應該使用回調函數嗎?

回答

1

同步在Java是(技術上)不是關於拒絕其他線程訪問對象,它大約確保使用同步鎖線程之間的獨特它使用(在同一時間)。因此,T2可以在T1同步鎖定的情況下訪問該對象,但在T1釋放它之前將無法獲得同步鎖定。

1

直到T1被使用元素右完成我應該鎖定陣列?

是,爲了避免競爭條件,這將是一個好主意。

應該怎樣做T2

看數組,然後讀取值。此時你知道沒人能修改它。當使用諸如monitors之類的鎖時,隊列被系統自動保存。因此,如果T2嘗試訪問由T1鎖定的對象,它將阻止(掛起),直到T1釋放鎖定。

示例代碼:

private Obect[] array; 
private static final Object lockObject = new Object(); 

public void modifyObject() { 
    synchronized(lockObject) { 
     // read or modify the objects 
    } 
} 

從技術上講,你也可以同步陣列本身上。

1

synchronize(鎖定)當你要有多個線程訪問的東西。

第二螺紋將要阻塞,直到第一線程釋放鎖(退出同步塊)

更細粒度的控制可以通過使用java.util.concurrent.locks和使用非阻塞檢查如果不被過希望線程阻塞。

1

1)基本上,是的。你不需要鎖定數組,你可以鎖定在更高的粒度級別(比如說,如果它是一個私有變量,封閉類)。重要的是,沒有部分代碼嘗試修改或從讀取數組而不保持相同的鎖定。如果違反此條件,可能會導致未定義的行爲(包括但不限於查看舊值,查看從不存在的垃圾值,拋出異常並進入無限循環)。

2)這部分取決於您正在使用的同步方案以及您所需的語義。使用標準​​關鍵字時,T2將無限期地阻塞,直到T1發佈監視器,此時T2將獲取監視器並繼續同步塊內的邏輯。

如果你想在當鎖定發生衝突,你可以使用顯式Lock對象行爲的細粒度控制。這些提供tryLock方法(兩者以超時,並立即返回),其根據是否可以得到鎖定返回truefalse。因此,如果不立即獲取鎖(例如註冊回調函數,遞增計數器並在重試之前給用戶提供反饋等),則可以測試返回值並採取任何您喜歡的操作。

但是,這種自定義反應很少是必需的,並且顯着增加了鎖定代碼的複雜性,更不用說如果忘記始終在finally塊中始終釋放鎖定時出現錯誤的可能性很大,當且僅當它被獲取成功等等。一般來說,只要去除​​就行了,除非您能證明它爲應用程序的所需吞吐量提供了一個重要的瓶頸。

1

你不鎖定一個變量;您鎖定了一個互斥鎖,它可以保護 特定範圍的代碼。規則很簡單:如果任何線程修改了一個對象,並且有多個線程訪問它(對於 ,任何原因),所有訪問都必須完全同步。通常 解決方案是定義一個互斥保護變量,請求 鎖定在其上,並釋放鎖一旦接入已完成。 當一個線程請求鎖,它被暫停,直到這個鎖 已被釋放。

在C++中,這是通常使用RAII以確保鎖是 解脫出來,不管如何將塊退出。在Java中, 同步塊將在開始 (等待它可用)時獲取鎖,並在程序離開塊時(出於任何原因)離開鎖。

1
T1 access element at index 0 first, then lock it. 

首先鎖定靜態最終互斥變量,然後訪問您的靜態變量。在類引用

static final Object lock = new Object(); 
synchronized(lock) { 
    // access static reference 
} 

或更好的訪問

synchronized(YourClassName.class) { 
    // access static reference 
}