3 回答

TA貢獻1821條經驗 獲得超5個贊
如注釋中所述,對類對象進行鎖定不會對該類的所有實例進行鎖定,而只會對表示您的 Account 類的 Class 對象進行鎖定。該鎖定與帳戶對象上的鎖定不兼容,因此您根本沒有同步操作。
鎖定單個帳戶對象可以在您的 for 循環(在 sumAccounts 中)內完成,但這不會阻止這樣的計劃發生:
- sumAccounts locks 'first' Account and reads balance (and releases lock again at end of the synchronized block taking the lock)
- system schedules a moneyTransfer() from 'first' to 'last'
- sumAccounts locks 'last' Account and reads balance, which includes the amount that was just transferred from 'first' and was already included in the sum
因此,如果您也想防止這種情況,您也需要同步帳戶上的moneyTransfer()處理.class(然后,這就過時了鎖定個人對象的需要)。

TA貢獻1834條經驗 獲得超8個贊
對于這種情況,您可以使用讀寫鎖定。傳輸貨幣方法將使用讀鎖定,因此可以并發執行。sumAccounts 方法將使用寫鎖定,因此當它執行時,不能從其他線程執行任何傳輸貨幣(或 sumAccounts)。
使用重入鎖并在類級別同步這兩種方法,將與您聲明的行為相同,因為它們不會允許并發執行 transferMoney 方法。
示例代碼:
final ReadWriteLock rwl = new ReentrantReadWriteLock();
public boolean transferMoney(Account from, Account to, int amount) {
rwl.readLock().lock();
try{
.... Your current code here
}
finally {
rwl.readLock().unlock();
}
}
public int sumAccounts(List<Account> accounts) {
rwl.writeLock().lock();
try{
// You dont need atomic integer here, because this can be executed by one thread at a time
int sum = 0;
for (Account a : accounts) {
sum += a.getBalance();
}
return sum;
}
finally {
rwl.writeLock().unlock();
}
}
此外,重入鎖的公平模式往往比非公平模式執行得更慢。有關詳細信息,請查看文檔。
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html

TA貢獻1909條經驗 獲得超7個贊
查看代碼非常困難,因為我們無法知道同步的對象帳戶是否在所有函數中都是完全相同的實例。
首先,我們必須同意余額之和金額的轉移是否是兩個應該同時運行的操作。
我預計在金額轉移之前和之后的余額總和是相同的。
此外,您正在使用余額的總和,這是錯誤的。您應該在要循環訪問的對象上進行同步。
現在,即使您確實在完全相同的實例中進行協調,您仍然可以有以下計劃:synchronized(Account.class)
Thread-1 (transfer)
locks from
Thread-2 (sum balance)
locks first object in the list and adds the balance to the running sum and moves to next object
Thread-1
locks to (which is the object Thread-2) processed
moves money from => to
您已經在增加之前用金額相加,并且根據計劃,您可以在扣除后添加金額。tofrom
問題是您要在傳輸中更新 2 個對象,但總和中只鎖定了 1 個對象。
我的建議是:
在同一個鎖上同步兩種方法,并使它們串行運行
當對象進入方法時設置一些臟標志,如果設置了,則在余額之和中跳過它們,并在所有更新完成后完成總和
transfer
你為什么還要在Java中這樣做?這應該在數據庫中使用具有 ACID 屬性的事務進行。
添加回答
舉報