java - Java中的多线程: how to transfer funds between accounts correctly?

标签 java multithreading

尝试在多线程环境中在条件账户之间进行转账,我的方法有多真实以及我错在哪里?

按照计划,我在 main 中创建一个新线程,在这个新线程中初始化一个 Transfer 类型的新类,在我从数据库中获取 2 个帐户的数据后,我随机确定我想要的金额随机转移。我将更改翻译并写回数据库。账户中所有资金的总和必须保持正确。也就是说,如果我们有 50 个账户,每个账户有 1000 block 钱(总共 50,000 block ),那么所有交易之后应该不会多,也不会超过 50,000。

如果线程不超过 5-10 个且线程 hibernate 时间超过 500 毫秒,则下面描述的方法有效。也许我解决问题的方法是错误的。我尝试使用tryLock,结果是一样的。总的来说,钱会变成正数,然后变成负数。

另外,我正在尝试在 Hibernate 上执行此操作。
我有什么:
1.对某个银行账户进行类-Account(@Entity)
2. TransferThread类扩展Thread
3. 类(class)转学 - 转学工作 4.主类

现在看起来像这样: 类帐户(设置/获取(我没有在这里写它们,但它们在那里)):

public class Account {
  private int id;
  private int money;

  public Account() {
  }
  public void widrawal(int sum) {
    money += sum;
  }
  public void send(int sum) {
    money -= sum;
  }
}

类TransferThread(根据想法,完成事务并 hibernate 随机时间(10次)):

public class TransferThread extends Thread {
  Transfer transfer= new Transfer();
  AtomicInteger atomicInteger = new AtomicInteger();

  public void run() {
    atomicInteger.set(10);
    while (atomicInteger.get() > 0) {
        //thread sleep for random time
        int a = (int) (Math.random() * (500 - 100)) + 100;
        try {
            transfer.transaction();
            atomicInteger.getAndDecrement();
            Thread.sleep(a);
        } catch (InterruptedException e) {
      }
    }
  }
}

类(class)转学:

public class Transfer {




public void transaction() throws InterruptedException {


    int sumSpis = (int) (Math.random() * 100) + 10;
    int ranAccount1 = (int) (Math.random() * 50) + 1;
    int ranAccount2 = (int) (Math.random() * 50) + 1;
    Account a1 = null;
    Account a2 = null;
    a1 = HibernateSessionFactoryUtil.getSessionFactory().openSession().get(Account.class, ranAccount1);
    a2 = HibernateSessionFactoryUtil.getSessionFactory().openSession().get(Account.class, ranAccount2);

    int fromId = a1.getId();
    int toId = a2.getId();

    if (fromId < toId) {
        synchronized (a1) {
            synchronized (a2) {
                transfer(a1, a2, sumSpis);

            }
        }
    } else {
        synchronized (a2) {
            synchronized (a1) {
                transfer(a1, a2, sumSpis);
            }
        }
    }

    System.out.println("amount: " + sumSpis);


}

public void transfer(Account account1, Account account2, int sum) {
    if (account1.getId() == account2.getId()) {
        System.out.println("same IDs");
        return;
    }

    if (account1.getMoney() < sum) {
        System.out.println("not enough account funds");
        return;
    }

    account1.widrawal(sum);
    account2.send(sum);

    Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
    Transaction tx = session.beginTransaction();
    session.update(account1);
    session.update(account2);
    tx.commit();
    session.close();
}
}

最佳答案

操作顺序应如下:获取 session 、启动数据库事务、从数据库获取 acc1 的数据、从数据库获取 acc2 的数据、转账、将 acc1 的数据保存到数据库、将 acc2 的数据保存到数据库、提交数据库事务。

在代码中,您从数据库获取帐户数据并将新数据保存在单独的 session 中,这意味着事务也是单独的。并且有可能在从数据库获取和保存到数据库之间,我的一个线程另一个线程已经更新了这些帐户的数据,并且您正在用过时的数据覆盖该数据。

关于java - Java中的多线程: how to transfer funds between accounts correctly?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61302164/

相关文章:

java - 不兼容的类型 - 发现 void java.util.Optional

java - 使用多个提供商的 OpenID Connect 示例?

java - 如何在java中为SVM算法生成HOG特征向量

java - 从列表中删除重复项而不对其进行迭代或使用集合

java - intel和AMD多线程的区别

java - HashMap 和 JDK 7

java - 如何将表格设置在窗口中央

multithreading - 在协程之间共享变量

Java线程向多个类发送相同的数据

java - Java使用者线程等待所有生产者线程完成