Java for newbies - DeadLock模仿

时间:2011-08-23 22:34:00

标签: java multithreading concurrency deadlock

我正在尝试编写一个非常简单的程序,它将模仿简单的DeadLock,其中线程A等待由线程B锁定的资源A,线程B等待线程A锁定的资源B。

这是我的代码:

//it will be my Shared resource
public class Account {
    private float amount;

    public void debit(double amount){
        this.amount-=amount;
    }

    public void credit(double amount){
        this.amount+=amount;
    }

}  

这是我的runnable,它在上面的资源上执行Operation:

public class BankTransaction implements Runnable {
    Account fromAccount,toAccount;
    float ammount;
    public BankTransaction(Account fromAccount, Account toAccount,float ammount){
        this.fromAccount = fromAccount;
        this.toAccount = toAccount;
        this.ammount = ammount;
    }

    private void transferMoney(){
        synchronized(fromAccount){
            synchronized(toAccount){
                fromAccount.debit(ammount);
                toAccount.credit(ammount);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                e.printStackTrace();
                }
                System.out.println("Current Transaction Completed!!!");
            }
        }
    }

    @Override
    public void run() {
        transferMoney();
    }

}

最后是我的主要课程:

    public static void main(String[] args) {

    Account a = new Account();
    Account b = new Account();
    Thread thread1 = new Thread(new BankTransaction(a,b,500));

    Thread thread2 = new Thread(new BankTransaction(b,a,500));
       thread1.start();  
       thread2.start();  
System.out.println("Transactions Completed!!!");

    }
}

为什么这段代码运行成功,我没有和deadLock?

5 个答案:

答案 0 :(得分:10)

它有潜在的用于死锁 - 但是两个锁一起获得的速度很快,以至于一个线程可以在另一个线程获得第一个之前获得两个锁。

在两个同步语句之间调用另一个Thread.sleep(500);并且 死锁:两个线程都会进入“他们的”外锁,睡眠,然后当他们醒来时他们都会发现已经获得了他们的“内在”锁定。

这是因为你的synchronized语句是反对称的:对于一个线程,外部同步锁是另一个线程的内部同步锁,反之亦然。

答案 1 :(得分:5)

其中一个线程可能会进入两个 synchronized个部分,完全阻止另一个线程直到它完成。

答案 2 :(得分:4)

你需要模拟'不幸的时机'。尝试在两个锁之间添加睡眠:

synchronized(fromAccount){
    Thread.sleep(2000);
    synchronized(toAccount){

答案 3 :(得分:2)

上面Jon建议的睡眠可以引入非确定性,你可以使用像闩锁这样的协调器来确定它。尽管如此,我认为它是一个测试问题:如何每次都证明死锁,这可能不是你想要的。

请参阅此code以获取示例,并blog post稍微描述一下。

答案 4 :(得分:0)

死锁的原因是线程A在A继续之前等待线程B释放一些资源;与线程B相同,它不会继续,直到线程A释放一些资源。换句话说,A和B永远等待彼此。

在代码片段中,synchronized可以阻止其他线程,因为此刻只有一个线程可以执行该块。 thread.sleep()将线程挂起500毫秒,然后继续。等待永远的相互条件并不满足,这就是为什么它不是死锁。

以下片段是说明死锁的一个很好的例子

public class threadTest{

    public class thread1 implements Runnable{
      private Thread _th2;
      private int _foo;

      public thread1(Thread th2){};
      public void run(){
        for(int i = 0; i<100; i++){foo += foo;};
        synchronized(this){this.notify()};
        synchronized(_th2){
            _th2.wait();
           _foo += _th2.foo;
           System.out.print(" final result " + _foo);
        }
      }
     }

     public class thread2 implements Runnable{
        private final thread1 _th1; private int _foo;
        public thread2(thread1 th1){};
        public void Run(){
           synchronized(_th1){_th1.wait()};
           synchronized(this){
             _foo += th1._foo();
             this.notify();                
           }
        }
     } 
    }
}

//忽略在类

中访问私有变量的方法

因为没有机制来确保两个线程的执行顺序,所以线程2很可能不会收到来自thread1的通知,因为它最近会启动,因此它会在继续执行之前等待通知。与thread1相同,它不能执行下一次执行,直到它收到来自thread2的通知。他们俩永远等待着彼此,典型的僵局。