Банкомат

  • 9
  • Недоступна
Разберись, как работает программа. Во время тестирования лог содержит следующее: ..... Добавляем 1000, на счету 1000 Тратим 100, на счету 800 Тратим 100, на счету 800 Тратим 100, на счету 800 Тратим 100, на счету 700 ..... Создан баг: деньги не правильно списываются со счета. Твоя задача:
Вы не можете решать эту задачу, т.к. не залогинены.
Комментарии (223)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Денис Измайлов Инженер- программист в CloudFactory
2 сентября, 07:52
И снова , условие: "Создан баг: деньги не правильно списываются со счета. Твоя задача: найти и исправить ошибку" так почему синхронизация по объекту в тредах НЕ решение, а синхронизация методов решение ? ОБА решения удовлетворяют поставленной задаче. Да. В реквайрементах описано про методы. НО ЭТО НЕ УСЛОВИЕ ЗАДАЧИ!!! ё-маё. ОТКУДА "реквайремнеты" вытекают из условия ?!
Torba Z Dimom
Уровень 23, Киев, Украина
6 августа, 22:17
Как и в многих предыдущих задачах самое сложное("долгое") - понять что делает програма. и чем дальше тем больше строк.... хорошая тренировка, но вот времени жрет вагон.
Саня
Уровень 30, Москва
29 июня, 10:43
Вот специально не стал перед отправкой синхронизировать deposit() -- и валидатор конечно же ругнулся -- а по факту всё работает правильно. Ну и зачем тогда этот метод синхронизовывать??
Галина
Уровень 18, Москва, Россия
21 сентября, 10:25
Я тоже не очень поняла зачем его синхронизировать, если там отдельная нить создается для вызова deposit().
Галина
Уровень 18, Москва, Россия
21 сентября, 10:26
Вроде как надо синхронизировать всё, что использует общие ресурсы. Но если для этого одна нить, то зачем ее синхронить?
Ivan
Уровень 18, Москва, Россия
12 апреля, 06:14
public BankAccount(String owner) { this(BigDecimal.ZERO, owner); } Подскажите пожалуйста почему в параметрах конструктора один параметр (owner), а в теле мы передаём два (BigDecimal.ZERO и owner)
"Почему бы и да"
Уровень 29
12 апреля, 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 марта, 23:55
Очень странное "правильное" решение и валидация, так как код из правильного решения - неправильный. При установке sync только на методы банкомата, нередко видим такой результат:
Недостаточно денег
Добавляем 1000, на счету 1000
Недостаточно денег
Тратим 100, на счету 900
А для того, чтобы требуемое условие всё-таки работало, необходимо поставить sync в метод run() класса SpendThread.
Maks Panteleev
Уровень 41, Москва, Россия
8 апреля, 08:28
я синки поставил на стринговые версии - валидатору не понравилось)
artlonwork
Уровень 27, Киев
10 марта, 14:06
Вставлю свои 5 копеек в этот "банкомат". 1. Поскольку задача называется "Банкомат", и в ней есть даже целый класс "Bankomat", то, анализируя работу программы, я пришел к выводу, что баланс нужно рассматривать не как количество денег на счету у какого-то очень уважаемого робота, а именно как количество наличности внутри самого банкомата. Есть внутри банкомата деньги, можем снять, нет внутри банкомата денег - стоим и смазываем масленкой наши металлические роботские суставы, чтобы не проржавели. 2. Если рассматривать задачу с такой стороны, тогда поток "addMoney" - это большой дядька с большим автоматом в большом бронежилете и с большим мешком денег, который раз в 1000мс засовывает в банкомат наличность. А остальные потоки - это пользователи с маленькими пластиковыми карточками, пытающиеся снять наличку из банкомата маленькими порциями. 3. В реальной жизни в один и тот же момент времени с банкоматом может работать только один человек, либо дядька с автоматом, либо пользователь с пластиковой карточкой. Пока кто-то из них возится с банкоматом, остальные стоят и ... ждут. 4. Поэтому мне кажется, что в этой задаче нужно реализовать именно эту логику, используя инструменты java, описанные в этой главе и предлагаемые в требованиях к этой задаче (synchronized).
Romanya System Engineer
4 марта, 13:16
Промотал коменты до самого конца, так и не нашел ответ на этот вопрос. Вот есть такая лекция: тут В ней такие строки:
Возможна ситуация, когда один поток изменил значение переменной, а второй не увидел этого изменения, потому что работал со своей, кэшированной копией переменной.
Смотрю я на вот это: И думаю, ну вот она эта ситуация. Добавил volatile к переменной balance. В надежде на то что 3 потока будут менять эту переменную но все будут видеть её новое значение и повторяющихся вычитаний не будет. Ан нет не работает. Почему где ошибаюсь подскажите? P.S (конечно решил с помощью sync и валидатора но хотелось бы разобраться) P. P. S (есть идея о том что потоки как бы не напрямую взаимодействуют с переменной, а через метод внутри класса. Но никаких фактов я про это не нашел) P. P. P. S (еще есть идея про то что методы переопределяют ссылку на эту переменную)
Vilgelm Brinster
Уровень 18, Караганда, Казахстан
9 апреля, 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, а они у них равны
VasliyD
Уровень 22, Москва
1 марта, 13:58
Не дочитав до конца задание, поставил sync на account в расходном и приходном run. По идее так ведь тоже можно? Правда, валидатор не принял, заставил сделать как велено.
Flexo Bending Unit #3370318
23 февраля, 09:55
Ну что тут можно сказати. Можно не читать условия, прочитать требования и добавить нужные ключи куда написано. Поздравляю, задача решена, действительно "лёгкая". Следующая! А можно попытаться вникнуть в механику задачи, и осознать, что из условия непонятно, какой баг, куда, почему, что требуется-то? Хотя бы потому, что по условию добавляли по 100, тратили по 1000, в задаче ровно наоборот. И в чём баг заключается, нужно поменять эти циферки местами? Где там что теряется? Ничего непонятно. Вроде становится всё более менее на свои места, если прогнать задачу с маркерами тредов (см ниже комментарий уважаемого @Kes) и внимательно посмотреть на вывод. И то, не с первого раза можно заметить, что там что-то не так (если треды начнут работать в строгой очерёдности, чисто случайно).
Flexo Bending Unit #3370318
23 февраля, 10:02
Вот правильный вывод, чего хотели добиться составители задачи после решения:
Добавляем 1000, на счету 1000
Thread-3 Тратим 100, на счету 900
Thread-2 Тратим 100, на счету 800
Thread-1 Тратим 100, на счету 700
Thread-2 Тратим 100, на счету 600
Thread-3 Тратим 100, на счету 500
Thread-1 Тратим 100, на счету 400
Thread-2 Тратим 100, на счету 300
Thread-3 Тратим 100, на счету 200
Thread-1 Тратим 100, на счету 100
Thread-2 Тратим 100, на счету 0
Thread-3 Недостаточно денег
Thread-1 Недостаточно денег
Thread-2 Недостаточно денег
...
а вот что было: - после пополнения счёта бывало, что недостаточно денег (но редко, я за первые два прогона этого не увидел) - треды-расходники тратили больше денег, чем их было на счёте, потому что переменная balance объекта account не успевала обновляться, т.к. не была синхронизирована. это, по всей видимости, по условию и является багом, но названо "При списании денег со счета теряются деньги."
Добавляем 1000, на счету 1000
Thread-1 Недостаточно денег        <--
Thread-2 Недостаточно денег        <--
Thread-3 Тратим 100, на счету 900
Thread-2 Тратим 100, на счету 800
Thread-1 Тратим 100, на счету 700
Thread-3 Тратим 100, на счету 600
Thread-2 Тратим 100, на счету 500
Thread-1 Тратим 100, на счету 400
Thread-2 Тратим 100, на счету 300  <--
Thread-3 Тратим 100, на счету 300  <--
Thread-1 Тратим 100, на счету 200
Thread-2 Тратим 100, на счету 100
Thread-3 Тратим 100, на счету 0
Thread-1 Недостаточно денег
Thread-2 Недостаточно денег
Thread-3 Недостаточно денег
...
Дмитрий
Уровень 20
22 февраля, 11:11
Сначала я решил, что раз тратят деньги 3 потока, а добавляет всего один, то синхронизировать нужно трату, но Валера сказал НЕТ - твоя логика не верна. Видимо потому что метод "deposit(BigDecimal money)" не атомарный, осуществляется в несколько этапов: создать переменную, получить текущее состояние банковского счета, увеличить его на значение "money", вывести на экран уведомление о том, что операция выполнена (хотя фактически это не так), присвоить переменной банковского счета новое значение. Мы как бы говорим потокам, тратящим бабло: парни погодите минуточку, не суетитесь, деньги начали поступать на счет)