[英]Best ways to write a method that updates two objects in a multithreaded java environment?
假設我們有一個名為AccountService的類來管理帳戶狀態。
AccountService定義為
interface AccountService{
public void debit(account);
public void credit(account);
public void transfer(Account account, Account account1);
}
鑒於此定義,實現transfer()的最佳方法是什么,以便您可以保證傳輸是原子操作。
我對引用Java 1.4代碼的答案以及可能使用Java 5中的java.util.concurrent資源的答案感興趣
同步兩個Account
對象並執行傳輸。 確保始終以相同的順序同步。 為此,請使Account
實現Comparable
,對兩個帳戶進行排序,然后按該順序進行同步。
如果您沒有訂購帳戶,如果一個線程從A轉移到B而另一個從B轉移到A,則會出現死鎖的可能性。
這個確切的例子在Java Concurrency in Practice的第207頁討論,這是任何進行多線程Java開發的人的重要書籍。 示例代碼可從發布者的網站獲得 :
您可能需要獲得完整的事務支持(如果它是一個真正的應用程序)。
解決方案的難度很大程度上取決於您的環境。 詳細描述您的系統,我們會盡力幫助您(什么樣的應用程序?它使用Web服務器?哪個Web服務器?什么用於存儲數據?等等)
如果您可以保證所有訪問都是通過傳輸方法進行的,那么最簡單的方法可能就是使傳輸成為同步方法。 這將是線程安全的,因為這可以保證在任何時候只有一個線程將運行傳輸方法。
如果其他方法也可以訪問AccountService,那么您可能決定讓它們都使用單個全局鎖。 一種簡單的方法是在同步(X){...}塊中包圍訪問AccountService的所有代碼,其中X是一些共享/單一對象實例(可能是AccountService實例本身)。 這將是線程安全的,因為任何時候只有一個線程將訪問AccountService,即使它們使用不同的方法。
如果仍然不夠,那么您將需要使用更復雜的鎖定方法。 一種常見的方法是在修改帳戶之前單獨鎖定帳戶...但是您必須非常小心地以一致的順序(例如通過帳戶ID)獲取鎖定,否則您將遇到死鎖。
最后,如果AccountService是一個遠程服務,那么你進入分布式鎖定領域....除非你擁有計算機科學博士學位和多年的研究預算,你應該避免去那里。
難道你不能避免使用AtomicReference<Double>
同步帳戶余額,以及get()
和set()
嗎?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.