void transfer(Account from,Account to,int money){ from.setAmount(from.getAmount()-money); to.setAmount(to.getAmount()+money); }
現在對其加鎖,加鎖後的程式碼如下
void transfer(Account from,Account to,int money){ synchronized(from){ synchronized(to){ from.setAmount(from.getAmount()-money); to.setAmount(to.getAmount()+money); } } }
synchronized,即對象鎖,第一個synchronized鎖住from對象,第二個synchronized鎖住to對象。
多執行緒情況下,在同一時刻多個執行緒中僅有一個執行緒能拿到這個物件鎖,對物件鎖裡面的程式碼段進行操作
但是加了物件鎖之後,可能存在死鎖!
transfer(a,b,100)和transfer(b,a,100)同時進行,即a向b轉帳的同時,b也在向a轉帳
【1】a向b轉賬,線程x拿到a這個物件鎖
【2】b向a轉賬,線程y拿到b這個物件鎖
操作【1】迫切需要b這個物件鎖,才能進行轉帳操作
操作【2】迫切需要a這個物件鎖,才能進行轉帳操作
兩個執行緒都在等待該群組中的其他執行緒釋放鎖,此時發生死鎖!
2、死鎖的解決
從那些方面下手呢?
【1】破除互斥等待
【2 】破除hold and wait ,即佔有等待
可以一次取得所有的資源,範例程式碼中並不是一次性取得from和to這兩個資源的,而是分佈取得的。
方法一:給to加上一個很短的超時時間,一旦嘗試獲取to超時,則立即釋放一開始持有的from鎖,過一段時間後
再重新嘗試取得from與to鎖。是建議的方法
方法二:給這段程式碼加上全域鎖,可以確保from與to同時拿到,轉帳作業完成後,釋放這個全域鎖。是比較安全的,但是銀行的帳戶數目眾多,轉帳操作十分頻繁,使用這種方式勢必會造成性能的嚴重下降
【3】破除循環等待
按順序獲取資源,依照Account的id的大小進行轉帳的操作,id比較小的帳戶先進行轉帳操作,id比較大的帳戶後進行
轉帳操作。但現實生活中,有些事物是沒有id的,即沒有順序性,這個時候需要強制給其加上順序性。
【4】破除無法剝奪的等待
加入超時,不得已的方法,用戶的此次轉帳操作失敗,用戶的體驗不好
個人推薦的解法:
犧牲使用者簡短的等待時間,使用【2】中的方法1
相關文章:
Java中死鎖的概念及解決方案 死鎖的概念與死鎖的條件以上是【JAVA】死鎖的產生與死鎖的解決的詳細內容。更多資訊請關注PHP中文網其他相關文章!