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

Java中的多线程:如何正确的在账户间转账?

魏硕
2023-03-14

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

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

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

另外,我正试着在Hibernate上这样做。< br >我所拥有的:< br> 1。类某银行账户- Account (@Entity)
2。类TransferThread扩展了Thread
3。类别转移-处理转移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) {
      }
    }
  }
}

类别转移:

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();
}
}

共有1个答案

丌官瀚
2023-03-14

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

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

 类似资料:
  • 问题内容: 我需要一个解决方案来正确停止Java中的线程。 我有实现Runnable接口的类: 我有启动和停止线程的类: 但是当我关闭时,我在类中得到了异常: 我正在使用JDK 1.6。所以问题是: 如何停止线程并且不引发任何异常? PS我不想使用;方法,因为它已过时。 问题答案: 在类中,你需要一种设置标志的方法,该标志通知线程它将需要终止,类似于你刚刚在类范围中使用的变量。 当你希望停止线程时

  • 我有一个耗时的任务,我想在用户输入“abort”时手动中止它。 可运行:

  • 我试图了解更多关于java线程转储的信息。我正在使用JBOSS EAP 4.3。 目前,我在我的一个环境中面临性能问题。突然,CPU利用率上升到700%。我把线程转储了,它是一个巨大的文件。 我在我的threaddump中发现了很多下面等待的线程条目。 我想从上面的等待线程中理解。是什么导致CPU利用率上升?

  • 问题内容: 我有用于在Java中创建线程的此类 控制台显示以下文本作为输出 我的代码创建了新线程: 我的问题是:为什么返回正确的线程名却返回另一个? 问题答案: 为什么要返回正确的线程名称而又返回其他? 您的课程,但随后您通过调用以下内容开始: 这是不正确的。这意味着创建的线程实际是 不 一样的。 应该实现而 不是 扩展线程。您的代码可以工作,因为线程也是可运行的。 因为有两个线程对象,所以当您调

  • 但这一个也不起作用。正确的答案是加入线程并删除2个睡眠: 我的问题是:为什么我的答案都不能被接受?我的实验室领导问,但他不能给我一个答案。在家里编写了测试代码,它似乎工作得很好。提前感谢您的帮助!

  • 问题内容: 我在掌握如何正确处理从以多线程方式使用Boost Asio的多线程程序创建子进程方面遇到一些麻烦。 如果我理解正确,那么在Unix世界中启动子进程的方法是先调用,然后调用。另外,如果我理解正确,则调用将复制所有文件描述符,依此类推,除非标记为,否则需要 在子进程中将其 关闭(从而在调用时被原子关闭)。 Boost Asio需要在被调用时得到通知,以便通过调用正确运行。但是,在多线程程序