亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 Java 中鎖定類的所有實例

在 Java 中鎖定類的所有實例

慕姐8265434 2022-09-22 16:28:03
我正在實施一個并行銀行系統,其中所有操作都可以同時運行。我已經實現了一個線程安全的方法,從帳戶傳輸到。transferMoneyamountfromtotransferMoney使用以下代碼實現:public boolean transferMoney(Account from, Account to, int amount) {        if (from.getId() == to.getId()){            return false;        }else if(from.getId() < to.getId()) {            synchronized(to) {                synchronized(from) {                    if(from.getBalance() >= amount) {                        from.setBalance(from.getBalance()-amount);                        to.setBalance(to.getBalance()+amount);                    }else {                        return false;                    }                }            }        }else {            synchronized(from) {                synchronized(to) {                    if(from.getBalance() >= amount) {                        from.setBalance(from.getBalance()-amount);                        to.setBalance(to.getBalance()+amount);                    }else {                        return false;                    }                }            }        }        return true;    }為了防止死鎖,我指定始終以相同的順序獲取鎖。為了確保以相同的順序獲取鎖,我使用的唯一 .IDAccount此外,我還實現了一個方法,該方法使用以下代碼匯總了銀行中的總金額:public int sumAccounts(List<Account> accounts) {    AtomicInteger sum = new AtomicInteger();    synchronized(Account.class) {        for (Account a : accounts) {            sum.getAndAdd(a.getBalance());        }    }    return sum.intValue();}問題當我同時運行時,即使沒有添加任何錢,我最終也會在銀行里得到更多(有時更少)的錢。根據我的理解,如果我通過 鎖定所有對象,難道我不應該得到正確的銀行總和,因為我正在阻止執行?sumAccounts()transferMoney()Accountsynchronized(Account.class)transferMoney()
查看完整描述

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(然后,這就過時了鎖定個人對象的需要)。


查看完整回答
反對 回復 2022-09-22
?
MMMHUHU

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


查看完整回答
反對 回復 2022-09-22
?
jeck貓

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 個對象。

我的建議是:

  1. 在同一個鎖上同步兩種方法,并使它們串行運行

  2. 當對象進入方法時設置一些臟標志,如果設置了,則在余額之和中跳過它們,并在所有更新完成后完成總和transfer

  3. 你為什么還要在Java中這樣做?這應該在數據庫中使用具有 ACID 屬性的事務進行。


查看完整回答
反對 回復 2022-09-22
  • 3 回答
  • 0 關注
  • 147 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號