Банкомат

  • 9
  • Недоступна
Разберись, как работает программа. Во время тестирования лог содержит следующее: ..... Добавляем 1000, на счету 1000 Тратим 100, на счету 800 Тратим 100, на счету 800 Тратим 100, на счету 800 Тратим 100, на счету 700 ..... Создан баг: деньги не правильно списываются со счета. Твоя задача:
Вы не можете решать эту задачу, т.к. не залогинены.
Комментарии (230)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Максим Белоусов
Уровень 18, Москва, Россия
7 декабря 2021, 11:23
Отличная задача в которой повторяем огромные числа BigDecimal, делегирование в методах и паттерн producer-consumer. Очень понравилось!
Sergey Kornilov
Уровень 35, Petropavlovsk, Казахстан
6 ноября 2021, 10:52
Всего эту задачу решили 23088 учеников.
Игорь Евгеньевич
Уровень 38, Хабаровск, Россия
14 октября 2021, 10:57
public synchronized void deposit(String money) { deposit(new BigDecimal(money)); } public synchronized void withdraw(String money) throws NotEnoughMoneyException { withdraw(new BigDecimal(money)); } В этих двух последних методах класса BankAccount в качестве аргумента передаётся строка. Далее они вызывают такой же метод принимающий BigDecimal и передают в него new BigDecimal с этой строкой. Вопрос! Как это работает?
Anonymous #2583212
Уровень 37
21 октября 2021, 10:44
Это рекурсия. Почитайте об этом
Dmitry Noskov
Уровень 49, Москва, Russian Federation
24 октября 2021, 17:00
это не рекурсия, это перегрузка методов:
public void deposit(BigDecimal money) {};
public void deposit(String money) {};
с точки зрения JVM это два разных независимых друг от друга метода. рекурсия была бы, если бы метод в своём теле вызывал себя.
Anonymous #2583212
Уровень 37
25 октября 2021, 04:00
Вы правы, я ошибся.
Денис Измайлов Инженер- программист в CloudFactory
2 сентября 2021, 07:52
И снова , условие: "Создан баг: деньги не правильно списываются со счета. Твоя задача: найти и исправить ошибку" так почему синхронизация по объекту в тредах НЕ решение, а синхронизация методов решение ? ОБА решения удовлетворяют поставленной задаче. Да. В реквайрементах описано про методы. НО ЭТО НЕ УСЛОВИЕ ЗАДАЧИ!!! ё-маё. ОТКУДА "реквайремнеты" вытекают из условия ?!
Torba Z Dimom
Уровень 23, Киев, Украина
6 августа 2021, 22:17
Как и в многих предыдущих задачах самое сложное("долгое") - понять что делает програма. и чем дальше тем больше строк.... хорошая тренировка, но вот времени жрет вагон.
Андрей Dungeon Master
9 ноября 2021, 09:41
вагон? пфф, ищешь метод, который отвечает на съем и взнос денег и синхронизируешь, 20 секунд решал задачу
Саня
Уровень 31, Москва
29 июня 2021, 10:43
Вот специально не стал перед отправкой синхронизировать deposit() -- и валидатор конечно же ругнулся -- а по факту всё работает правильно. Ну и зачем тогда этот метод синхронизовывать??
Галина
Уровень 19, Москва, Россия
21 сентября 2021, 10:25
Я тоже не очень поняла зачем его синхронизировать, если там отдельная нить создается для вызова deposit().
Галина
Уровень 19, Москва, Россия
21 сентября 2021, 10:26
Вроде как надо синхронизировать всё, что использует общие ресурсы. Но если для этого одна нить, то зачем ее синхронить?
Ivan
Уровень 19, Москва, Россия
12 апреля 2021, 06:14
public BankAccount(String owner) { this(BigDecimal.ZERO, owner); } Подскажите пожалуйста почему в параметрах конструктора один параметр (owner), а в теле мы передаём два (BigDecimal.ZERO и owner)
"Почему бы и да"
Уровень 33
12 апреля 2021, 12:56
Таким образом мы вызываем конструктор с двумя параметрами, вот этот:
public BankAccount(BigDecimal balance, String owner) {
       this.balance = balance;
       this.owner = owner;
   }
и передаем в него Bigedecimal.ZERO и owner. Тоесть, если мы создаем объект и передаем в конструктор только один параметр, например new BankAccount (Ivan), то поле balance будет проинициализировано заначением 0. new BankAccount (Ivan) это тоже самое, что new BankAccount (Invan, BigDecimal. ZERO).
Roman Grand
Уровень 35, Новосибирск, Россия
17 марта 2021, 23:55
Очень странное "правильное" решение и валидация, так как код из правильного решения - неправильный. При установке sync только на методы банкомата, нередко видим такой результат:
Недостаточно денег
Добавляем 1000, на счету 1000
Недостаточно денег
Тратим 100, на счету 900
А для того, чтобы требуемое условие всё-таки работало, необходимо поставить sync в метод run() класса SpendThread.
Maks Panteleev Java Developer в Bell Integrator
8 апреля 2021, 08:28
я синки поставил на стринговые версии - валидатору не понравилось)
artlonwork
Уровень 28, Киев
10 марта 2021, 14:06
Вставлю свои 5 копеек в этот "банкомат". 1. Поскольку задача называется "Банкомат", и в ней есть даже целый класс "Bankomat", то, анализируя работу программы, я пришел к выводу, что баланс нужно рассматривать не как количество денег на счету у какого-то очень уважаемого робота, а именно как количество наличности внутри самого банкомата. Есть внутри банкомата деньги, можем снять, нет внутри банкомата денег - стоим и смазываем масленкой наши металлические роботские суставы, чтобы не проржавели. 2. Если рассматривать задачу с такой стороны, тогда поток "addMoney" - это большой дядька с большим автоматом в большом бронежилете и с большим мешком денег, который раз в 1000мс засовывает в банкомат наличность. А остальные потоки - это пользователи с маленькими пластиковыми карточками, пытающиеся снять наличку из банкомата маленькими порциями. 3. В реальной жизни в один и тот же момент времени с банкоматом может работать только один человек, либо дядька с автоматом, либо пользователь с пластиковой карточкой. Пока кто-то из них возится с банкоматом, остальные стоят и ... ждут. 4. Поэтому мне кажется, что в этой задаче нужно реализовать именно эту логику, используя инструменты java, описанные в этой главе и предлагаемые в требованиях к этой задаче (synchronized).
Romanya Java Developer в Региональный Информа
4 марта 2021, 13:16
Промотал коменты до самого конца, так и не нашел ответ на этот вопрос. Вот есть такая лекция: тут В ней такие строки:
Возможна ситуация, когда один поток изменил значение переменной, а второй не увидел этого изменения, потому что работал со своей, кэшированной копией переменной.
Смотрю я на вот это: И думаю, ну вот она эта ситуация. Добавил volatile к переменной balance. В надежде на то что 3 потока будут менять эту переменную но все будут видеть её новое значение и повторяющихся вычитаний не будет. Ан нет не работает. Почему где ошибаюсь подскажите? P.S (конечно решил с помощью sync и валидатора но хотелось бы разобраться) P. P. S (есть идея о том что потоки как бы не напрямую взаимодействуют с переменной, а через метод внутри класса. Но никаких фактов я про это не нашел) P. P. P. S (еще есть идея про то что методы переопределяют ссылку на эту переменную)
Vilgelm Brinster
Уровень 18, Караганда, Казахстан
9 апреля 2021, 03:40
public synchronized void withdraw(BigDecimal money) throws NotEnoughMoneyException {
        BigDecimal newBalance = balance.subtract(money);

        if (newBalance.compareTo(BigDecimal.ZERO) < 0) throw new NotEnoughMoneyException();

        balance = newBalance;
        System.out.println("Тратим " + money + ", на счету " + balance);
    }
Дело в том, что сначала потоки получают значение balance и только спустя несколько строк вносят в него новое значение. Таким образом первый поток получил newBalance, равный к примеру 300 и остановился. Значение balance каким было, таким и осталось! Второй поток получил для своей локальной newBalance те же 300, потому что balance первым потоком не менялся. Дальше они проходят до конца метода и только в предпоследней строчке они заносят свои значения newBalance, а они у них равны