当前位置: 首页 > 知识库问答 >
问题:

两个对象上的Java同步会导致死锁

湛光明
2023-03-14

我需要在账户之间实现一些基本的资金转移逻辑。为了保持转账的一致性,我利用了同步锁。

这是帐户对象:

class Account {
    UUID id;
    double balance;
}

这是在transfer worker类中:

    public void transfer(Account source, Account target) throws InterruptedException {
        Object firstLock = target.id.compareTo(source.id)  > 0 ? target : source;
        Object secondLock = target.id.compareTo(source.id)  < 0 ? target : source;
        synchronized (firstLock) {
            synchronized (secondLock) {
                // Money tranfer logic
            }   
        }
    }

我的问题是,如果source Account没有足够的资金,我计划等待该线程,直到它从其他运营中获得资金。对于这个,我一直在等待源帐户。但它以死锁告终,因为目标帐户锁仍在我的帐户上。我怎样才能做到这一点?你能告诉我解决这个问题的正确方法吗?

这就是我试图推迟资金转移的来源账户

    public void transfer(Account source, Account target) throws InterruptedException {
        Object firstLock = target.id.compareTo(source.id)  > 0 ? target : source;
        Object secondLock = target.id.compareTo(source.id)  < 0 ? target : source;
        synchronized (firstLock) {
            synchronized (secondLock) {
                while(source.balance <= 0 ) {
                    source.wait();
                }
                
                // Money tranfer logic
                
                source.notifyAll();
            }   
        }
    }

谢谢。

共有1个答案

苍恩
2023-03-14

每当您运行任何等待代码时,您都需要处理InterruptedExctive。此外,在调试时添加特定的等待时间也是一个很好的做法,这样您就可以在特定的等待时间后重新加载您的当时循环。
以下是一个修改代码的示例,它可能会帮助您

synchronized (firstLock) {
        synchronized (secondLock) {
            while(s.balance <= 0 ) {
                
                //surround with InterruptedException otherwise code won't execute
                try {
                    s.wait(1000); // it is good to wait for specific milliseconds, in this case it's 1000 millis.
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
            // Money transfer logic
            
            s.notifyAll();
        }   
    }
    

对不起,但是你已经改变了你的问题,所以我也在更新我的答案

这里新添加的代码,你不能使用静态源代码,目标。当循环运行时,你需要从数据库更新。

public class Z {
public static void main(String a[]){

    Account s = new Account("1");
    Account t = new Account("4");
    
    try {
        transfer(s, t);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }


}
public static void transfer(Account source, Account target) throws InterruptedException {
    Account firstLock = target.id.compareTo(source.id)  > 0 ? target : source;
    Account secondLock = target.id.compareTo(source.id)  < 0 ? target : source;

    double sourceBalance = 0;
    double targetBalance = 0;

    synchronized (firstLock) {
        synchronized (secondLock) {
            while(sourceBalance <= 4 ) {
                source.wait(1000);
                System.out.println("waiting... ");
                sourceBalance = sourceBalance+1; //get source balance from somewhere else realtime. for me im just updating
            }
            
            // Money tranfer logic
            targetBalance = 0; //get target balance from server or where you stored;
            targetBalance +=sourceBalance; 
            //send target balance where you want
            System.out.println("Money transferred");
            
            source.notifyAll();
        }   
    }
}


}
class Account {
    String id;
    public Account(String id){
        this.id = id;
    }
}
 类似资料:
  • 我只在一个字符串对象上找到了同步的答案,而不是两个。 这不是一项真正的任务,而是一项任务。我有一个图书馆可以把钱从一个账户转到另一个账户。我无法访问帐户对象以锁定它。我只能用图书馆里的东西。传输(字符串从、字符串到),这不是线程安全的。我有一个帐户ID为字符串的方法。我需要在没有死锁的情况下锁定这两个字符串。 到目前为止,我所做的是: > 使用创建了新字符串。intern方法(字符串fr=from

  • 问题内容: 我想知道如果在同一个对象上同步两次,在Java中是否会出现任何奇怪的行为? 场景如下 两种方法都使用该对象并对其进行同步。当第一个方法调用第二个方法时,它会被锁定而停止吗? 我不这么认为,因为它是同一个线程,但是我不确定是否可能会出现其他任何奇怪的结果。 问题答案: 同步块使用 可重入 锁,这意味着如果线程已经持有该锁,则它可以重新获取它而不会出现问题。因此,您的代码将按预期工作。 请

  • 我遇到了一些使用c#的/关键字进行异步编程的最佳实践(我是c# 5.0的新手)。 给出的建议之一如下: 稳定性:了解您的同步上下文 ...一些同步上下文是不可重入的和单线程的。这意味着在给定时间只能在上下文中执行一个工作单元。这方面的一个例子是Windows UI线程或ASP.NET请求上下文。在这些单线程同步上下文中,很容易死锁。如果您从单线程上下文中生成一个任务,然后在上下文中等待该任务,您的

  • 但是,这并不适用于String类。请参见下面的代码: 这是因为字符串类和自声明类之间的差异吗?谢谢你的帮助!

  • 我试图理解java中同步块的概念。根据我读过的文档,我明白如果我们获取一个锁(使用实例变量的同步块),那么我们就不能在该类中的同一对象上获取同步锁。但是当我尝试实际使用以下片段时,我发现我的理解出了问题。 即我能够同时以两种不同的方法获取锁(同一实例变量上的同步块)。当线程启动时,它将转到run方法并无限期地等待,并且不会从同步块中出来。同时,如果我使用相同的线程调用stop方法,它会进入同步块并

  • 我正在寻找有关同步块的澄清。考虑一下这个类 - A是单例。getValue在整个应用程序中被多个线程大量访问。我添加了一个新方法remove,它从映射中删除一个键。如果如上所述执行删除, 当线程位于remove方法的同步块中时,我假设它将获取map对象上的锁。这是否意味着其他试图通过getValue方法访问映射的线程将被阻止?(我希望他们这样做。) 当remove方法的同步块中没有线程时,访问ge