Многотопоточность в Java: как корректно перемещать средства между аккаунтами?

Собственно, пытаюсь сделать перевод между условными аккаунтами в многопоточной среде, на сколько верно пытаюсь реализовать?
По задумке я создаю новый поток в нем инициализирую новый класс типа Трансфер, после чего в этом классе беру их БД данные 2 аккаунтов, которые определяю случайным образом, сумму которую хочу перевести случайную, выполняю перевод и записываю изменения обратно в БД. При чем сумма всех средств на счетах должна оставаться начальной.

Описанный ниже подход работает есть потоков не больше 5-10 и потоки спят более чем по 500мс. Возможно у меня неправильный подход к решению проблемы. Относительно заботы с tryLock, пробовал, тоже самое получается, суммарно деньги то уходят в плюс, то в минус.

Плюсом ко всему, это чудо я пытаюсь сделать на Hibernate.
Что есть:
1. Класс какого-то аккаунта - Account (@Entity)
2. Класс унаследованный от потока, в котором я работаю непосредственно с run() - TransferThread extends Thread
3. Класс Transfer в котором происходит взаимодействие с аккаунтом у конкретного потока.
4. Класс Main

Собственно сейчас это выглядит так:
Класс Account (set/get я опустил чтобы не громоздить код):

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 (в нем, по задумке, нить отрабатывает транзакцию и засыпает на случайное время и так 10 раз):

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

  public void run() {
    atomicInteger.set(10);
    while (atomicInteger.get() > 0) {
        //нить засыпает на случайное время
        int a = (int) (Math.random() * (500 - 100)) + 100;
        try {
            transfer.transaction();
            atomicInteger.getAndDecrement();
            Thread.sleep(a);
        } catch (InterruptedException e) {
      }
    }
  }
}

Класс Transfer:

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

    System.out.println("**************************************");
    if (fromId < toId) {
        synchronized (a1) {
            synchronized (a2) {
                transfer(a1, a2, sumSpis);

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

    System.out.println("сумма перевода: " + sumSpis);
    System.out.println("денег на аккаунте: " + a1.getId() + " стало " + a1.getMoney() + " денег на аккаунте: " + a2.getId() + " стало " + a2.getMoney());
    System.out.println("**************************************");

}

public void transfer(Account account1, Account account2, int sum) {
    if (account1.getId() == account2.getId()) {
        System.out.println("Одинаковые ИД");
        return;
    }

    if (account1.getMoney() < sum) {
        System.out.println("На аккаунте списания недостаточно средств денег");
        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();
}
}

Ответы (0 шт):