當兩個或多個執行緒互相等待時被阻塞,就會發生死鎖。例如,第乙個執行緒被第二個執行緒阻塞,它在等待第二個執行緒持有的乙個資源。而第二個執行緒在獲得第乙個執行緒持有的某個資源之前不會釋放這個資源。由於第乙個執行緒在獲得第二個執行緒持有的那個資源之前不會釋放它自己所持有的資源,而第二個執行緒在獲得第乙個執行緒持有的乙個資源之前也不會釋放它所持有的資源,於是這兩個執行緒就被死鎖。
在編寫多執行緒**時,死鎖是最難處理的問題之一。因為死鎖可能在最意想不到的地方發生,所以查詢和修正它既費時又費力。例如,試考慮下面這段鎖定了多個物件的**。
public int sumarrays(int a1, int a2)
}public long lockorder()
public int array()
}class someclass implements runnable
synchronized(first) { // 按正確的順序鎖定物件。
synchronized(last) {
int arr1 == a1.array();
int arr2 == a2.array();
for (int i=0; i
在第乙個示例中,arraywithlockorder
類是作為陣列的乙個包裝提供的。每建立該類的乙個新物件,該類就將static num_locks
變數加 1。乙個單獨的lock_order
例項變數被設定為num_locks
static
變數的當前值。這可以保證,對於該類的每個物件,lock_order
變數都有乙個獨特的值。lock_order
例項變數充當此物件相對於該類的其他物件的鎖定順序指示器。
請注意,static
num_locks
變數是在synchronized
語句中進行操作的。這是必須的,因為物件的每個例項共享該物件的static
變數。因此,當兩個執行緒同時建立arraywithlockorder
類的乙個物件時,如果操作static
num_locks
變數的**未作同步處理,該變數就可能被破壞。對此**作同步處理可以保證,對於arraywithlockorder
類的每個物件,lock_order
變數都有乙個獨特的值。
此外還更新了sumarrays
方法,以使它包括確定正確鎖定順序的**。在請求鎖之前,將查詢每個物件以獲得它的鎖定順序。編號較小的首先被鎖定。此**可以保證,不管各物件是以什麼順序傳給此方法,它們總是被以相同的順序鎖定。
static num_locks
域和lock_order
域都是作為long
型別實現的。long
資料型別是作為 64 位有符號二進位制補碼整數實現的。這意味著在建立 9,223,372,036,854,775,807 個物件之後,num_locks
和lock_order
的值將重新開始。您未必會達到這個極限,但在適當的條件下這是可能發生的。
實現嵌入的鎖定順序需要投入更多的工作,使用更多的記憶體,並會延長執行時間。但是,如果您的**中可能存在這些型別的死鎖,您也許會發現值得這樣做。如果您無法承受額外的記憶體和執行開銷,或者不能接受num_locks
或lock_order
域重新開始的可能性,則您在建立鎖定物件的預定義順序時應該仔細斟酌。
以全域性的固定順序獲取多個鎖來
當兩個或多個執行緒互相等待時被阻塞,就會發生死鎖。例如,第乙個執行緒被第二個執行緒阻塞,它在等待第二個執行緒持有的乙個資源。而第二個執行緒在獲得第乙個執行緒持有的某個資源之前不會釋放這個資源。由於第乙個執行緒在獲得第二個執行緒持有的那個資源之前不會釋放它自己所持有的資源,而第二個執行緒在獲得第乙個執...
以全域性的固定順序獲取多個鎖來避免死鎖
當兩個或多個執行緒互相等待時被阻塞,就會發生死鎖。例如,第乙個執行緒被第二個執行緒阻塞,它在等待第二個執行緒持有的乙個資源。而第二個執行緒在獲得第乙個執行緒持有的某個資源之前不會釋放這個資源。由於第乙個執行緒在獲得第二個執行緒持有的那個資源之前不會釋放它自己所持有的資源,而第二個執行緒在獲得第乙個執...
以乙個固定 全域性次序獲取多個鎖
當兩個或多個執行緒互相等待時被阻塞,就會發生死鎖。例如,第乙個執行緒被第二個執行緒阻塞,它在等待第二個執行緒持有的乙個資源。而第二個執行緒在獲得第乙個執行緒持有的某個資源之前不會釋放這個資源。由於第乙個執行緒在獲得第二個執行緒持有的那個資源之前不會釋放它自己所持有的資源,而第二個執行緒在獲得第乙個執...