猿问

死锁的例子

我检查了很多网站,唯一的例子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);


    }

}

但是如果我们在一个同步块之后使用一个同步块,就不会有死锁。

如果这是导致死锁的唯一方法,那我们为什么不使用两个单独的同步块呢?如果还有其他方法导致死锁,请举例说明。



一只斗牛犬
浏览 108回答 1
1回答

江户川乱折腾

考虑一家拥有数千个类型的银行账户的银行Account。现在让我们看看为什么这段代码会导致死锁:public void transfer(Account a,Account b,int amount)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; synchronized(a)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a.withdraw(amount);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.print(amount+" is withdrawn from account a\n");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try{Thread.sleep(500);}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; catch(Exception e){System.out.println(e);}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; synchronized(b)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b.deposit(amount);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.print(amount+" is deposited into account b\n");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }让有线程tA和线程tB。如果线程在线程同时运行时tA运行以下代码&nbsp;,则可能会出现死锁,因为如果我们查看以下顺序:transfer(accountA, AccountB)tBtransfer(accountB, accountA)面向:synchronized(accountA)待定:synchronized(accountB)tA:尝试锁定对象AccountB,但锁定由 tB 持有 =>死锁我们看到两者之间存在循环依赖关系,不允许其中一个线程继续前进。如果我们查看您更新的代码:public void transfer(Account a,Account b,int amount)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; synchronized(a)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a.withdraw(amount);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.print(amount+" is withdrawn from account a\n");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try{Thread.sleep(500);}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; catch(Exception e){System.out.println(e);}&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; synchronized(b)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b.deposit(amount);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.print(amount+" is deposited into account b\n");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }我们必须采取以下假设:账户 a 有无限的资金,因为它可能是 a.balance < amount,这意味着 a.balance < 0,这打破了我们总是有余额 >=0 的不变量。我们允许不一致,例如,如果我们想汇总所有当前现金,我们将汇总少于实际金额,因为您当前的代码允许我们这样做。如果我们尝试修复代码,我们必须在更新余额之前确保 a.balance >= amount。现在让我们看看以下场景:账户a有balance < amount我们必须等到a.balance >= amount从帐户中取款a因为我们在这个线程中保持 Account 的锁a,所以没有其他线程可以更新a.balance=> 我们遭受饥饿要解决这些问题,您要么必须使用监视器或条件来检查 a.balance>=amount 是否要进行,并将线程置于阻塞状态,以便线程可以进行或更新您的代码,以便锁定总是以相同的顺序获取。解决方案#1:获取对象锁的唯一顺序如果我们使用唯一的顺序获取对象的锁,我们可以确保不会发生死锁,因为我们以指定的顺序获取锁,不允许任何循环依赖,否则称为死锁。public void transfer(Account a,Account b,int amount)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;//define a specific order, in which locks are acquired&nbsp; &nbsp; &nbsp; &nbsp;//the id's of all accounts are unique!&nbsp; &nbsp; &nbsp; &nbsp;if(a.id<b.id){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; synchronized(a){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; synchronized(b){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//do operations here&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;}else{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; synchronized(b){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; synchronized(a){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//do operations here&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; }解决方案 #2:使用生产者-消费者模式来检查a.balance>=amount.public void transfer(Account a,Account b,int amount){&nbsp; &nbsp; while(true){&nbsp; &nbsp; &nbsp; synchronized(a){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(a.balance>=amount){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //do operations here&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; try{Thread.sleep(500);} //Use this as a backoff, as otherwise you'd likely get high congestion&nbsp; &nbsp; &nbsp; &nbsp; catch(Exception e){System.out.println(e);}&nbsp; &nbsp; }&nbsp; &nbsp; synchronized(b)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;//do operations here&nbsp; &nbsp; }}
随时随地看视频慕课网APP

相关分类

Java
我要回答