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

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

死鎖的例子

死鎖的例子

一只斗牛犬 2023-06-04 19:42:10
我檢查了很多網站,唯一的例子deadlock就是這樣。synchronized塊中總有塊synchronized。(方法withdraw被鎖定a,方法deposit被鎖定b。)class Account{    int balance;    Account(int amount)    {balance = amount;}    void withdraw(int amount)    {balance-=amount;}    void deposit(int amount)    {balance+=amount;}}class Threaddemo extends Thread{    Account a,b;    int amount;    Threaddemo(Account a,Account b,int amount)    {        this.a=a;this.b=b;this.amount=amount;        start();    }    public void run()    {        transfer(a,b,amount);    }    public void transfer(Account a,Account b,int amount)    {        synchronized(a)        {            a.withdraw(amount);            System.out.print(amount+" is withdrawn from account a\n");            try{Thread.sleep(500);}            catch(Exception e){System.out.println(e);}            synchronized(b)            {                b.deposit(amount);                System.out.print(amount+" is deposited into account b\n");            }        }    }}class U3{    public static void main(String[] args)     {        Account a = new Account(1000);        Account b = new Account(2000);        new Threaddemo(a,b,100);        new Threaddemo(b,a,200);    }}但是如果我們在一個同步塊之后使用一個同步塊,就不會有死鎖。如果這是導致死鎖的唯一方法,那我們為什么不使用兩個單獨的同步塊呢?如果還有其他方法導致死鎖,請舉例說明。
查看完整描述

1 回答

?
江戶川亂折騰

TA貢獻1851條經驗 獲得超5個贊

考慮一家擁有數千個類型的銀行賬戶的銀行Account。現在讓我們看看為什么這段代碼會導致死鎖:


public void transfer(Account a,Account b,int amount)

    {

        synchronized(a)

        {

            a.withdraw(amount);

            System.out.print(amount+" is withdrawn from account a\n");


            try{Thread.sleep(500);}

            catch(Exception e){System.out.println(e);}


            synchronized(b)

            {

                b.deposit(amount);

                System.out.print(amount+" is deposited into account b\n");

            }

        }

    }

讓有線程tA和線程tB。如果線程在線程同時運行時tA運行以下代碼 ,則可能會出現死鎖,因為如果我們查看以下順序:transfer(accountA, AccountB)tBtransfer(accountB, accountA)

  1. 面向:synchronized(accountA)

  2. 待定:synchronized(accountB)

  3. tA:嘗試鎖定對象AccountB,但鎖定由 tB 持有 =>死鎖

我們看到兩者之間存在循環依賴關系,不允許其中一個線程繼續前進。

如果我們查看您更新的代碼:

public void transfer(Account a,Account b,int amount)

    {

        synchronized(a)

        {

            a.withdraw(amount);

            System.out.print(amount+" is withdrawn from account a\n");


            try{Thread.sleep(500);}

            catch(Exception e){System.out.println(e);}

        }

        synchronized(b)

        {

            b.deposit(amount);

            System.out.print(amount+" is deposited into account b\n");

        }

    }

我們必須采取以下假設:

  • 賬戶 a 有無限的資金,因為它可能是 a.balance < amount,這意味著 a.balance < 0,這打破了我們總是有余額 >=0 的不變量。

    • 我們允許不一致,例如,如果我們想匯總所有當前現金,我們將匯總少于實際金額,因為您當前的代碼允許我們這樣做。

如果我們嘗試修復代碼,我們必須在更新余額之前確保 a.balance >= amount?,F在讓我們看看以下場景:

  1. 賬戶abalance < amount

  2. 我們必須等到a.balance >= amount從帳戶中取款a

  3. 因為我們在這個線程中保持 Account 的鎖a,所以沒有其他線程可以更新a.balance=> 我們遭受饑餓

要解決這些問題,您要么必須使用監視器或條件來檢查 a.balance>=amount 是否要進行,并將線程置于阻塞狀態,以便線程可以進行或更新您的代碼,以便鎖定總是以相同的順序獲取。

解決方案#1:獲取對象鎖的唯一順序

如果我們使用唯一的順序獲取對象的鎖,我們可以確保不會發生死鎖,因為我們以指定的順序獲取鎖,不允許任何循環依賴,否則稱為死鎖。

public void transfer(Account a,Account b,int amount)

    {

       //define a specific order, in which locks are acquired

       //the id's of all accounts are unique!

       if(a.id<b.id){

          synchronized(a){

            synchronized(b){

               //do operations here

            }

          }

       }else{

          synchronized(b){

            synchronized(a){

               //do operations here

            }

          }

       }

    }

解決方案 #2:使用生產者-消費者模式來檢查a.balance>=amount.


public void transfer(Account a,Account b,int amount)

{

    while(true){

      synchronized(a){

          if(a.balance>=amount){

              //do operations here

          }

      }


        try{Thread.sleep(500);} //Use this as a backoff, as otherwise you'd likely get high congestion

        catch(Exception e){System.out.println(e);}

    }

    synchronized(b)

    {

       //do operations here

    }

}


查看完整回答
反對 回復 2023-06-04
  • 1 回答
  • 0 關注
  • 143 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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