Некорректное изменение значений при работе с потоками
Создаю n независимых потоков, после выполнения метода transaction должно происходить изменение значений (c одного счета должны уходить деньги на другой), но после выполнения, значения не изменяются. По умолчанию в методе save добавляю на каждый счет 10000. Должно произойти 9 транзакций и после этого программа должна завершится.
Сущность Account:
@Entity
@Table
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Account {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
@Getter
private long id;
@Column(name= "money")
@Getter
@Setter
private int money;
public static AtomicInteger numberTransaction = new AtomicInteger();
public int withdrawal(int value) {
return money += value;
}
public int send(int value) {
return money -= value;
}
}
Репозиторий:
public interface AccountRepository extends CrudRepository<Account,Long> {
}
Сервис:
@Service
public class AccountService extends Thread {
private final AccountRepository accountRepository;
public AccountService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}
public Iterable<Account> findAllAccount() {
return accountRepository.findAll();
}
public Account save(Account account) {
account.setMoney(10000);
return accountRepository.save(account);
}
public Long countAccount() {
return accountRepository.count();
}
public Account update(Account category) {
return accountRepository.save(category);
}
public void delete(Long id) {
accountRepository.deleteById(id);
}
public void transaction(Long accountIdOne, Long accountIdTwo, int value) {
Account accountOne = accountRepository.findById(accountIdOne).orElseThrow();
Account accountTwo = accountRepository.findById(accountIdTwo).orElseThrow();
synchronized (accountOne) {
synchronized (accountTwo) {
accountOne.withdrawal(value);
this.update(accountOne);
accountTwo.send(value);
this.update(accountTwo);
}
}
}
public void test() {
new Thread(new Runnable() {
@Override
public void run() {
while (Account.numberTransaction.get() < 10) {
int sleep = (int) (Math.random() * (2000 - 1000)) + 1000;
try {
transaction(1L, 2L, 1000);
Account.numberTransaction.incrementAndGet();
Thread.sleep(sleep);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
}
}
}).start();
}
}
Тест:
@SpringBootTest
class AccountTransferApplicationTests {
@Autowired
private AccountService accountService;
@Test
void contextLoads() throws InterruptedException {
Account account = new Account();
Account account1 = new Account();
accountService.save(account);
accountService.save(account1);
for(int i = 0; i < accountService.countAccount(); i++) {
accountService.test();
accountService.join();
}
}
}
Ответы (1 шт):
Автор решения: Денис Старакожев
→ Ссылка
Не буду говорить на сколько вся задумка объединить управление потоками, транзакциями и данными в одном сервисе выглядит сомнительно.
Скажу почему не работает так как вы задумали.
- Ваш AccountService наследует Thread и является потоком.
- метод test() вызывает ваш метод transaction() создавая новый поток.
- Вы запускаете логику транзакции в одном потоке (new Thread() в методе test), а ждете выполнения другого потока (accountService), по этому фактически не дожидаетесь завершения логики, по этому и данные не сохраняются