Банкомат

  • 9
  • Недоступна
Разберись, как работает программа. Во время тестирования лог содержит следующее: ..... Добавляем 1000, на счету 1000 Тратим 100, на счету 800 Тратим 100, на счету 800 Тратим 100, на счету 800 Тратим 100, на счету 700 ..... Создан баг: Деньги не правильно списываются со счета. Найти и исправить ошиб
Вы не можете решать эту задачу, т.к. не залогинены.
Комментарии (223)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий вы должны авторизоваться
Romanya System Engineer
позавчера, 13:16
Промотал коменты до самого конца, так и не нашел ответ на этот вопрос. Вот есть такая лекция: тут В ней такие строки:
Возможна ситуация, когда один поток изменил значение переменной, а второй не увидел этого изменения, потому что работал со своей, кэшированной копией переменной.
Смотрю я на вот это: И думаю, ну вот она эта ситуация. Добавил volatile к переменной balance. В надежде на то что 3 потока будут менять эту переменную но все будут видеть её новое значение и повторяющихся вычитаний не будет. Ан нет не работает. Почему где ошибаюсь подскажите? P.S (конечно решил с помощью sync и валидатора но хотелось бы разобраться) P. P. S (есть идея о том что потоки как бы не напрямую взаимодействуют с переменной, а через метод внутри класса. Но никаких фактов я про это не нашел) P. P. P. S (еще есть идея про то что методы переопределяют ссылку на эту переменную)
VasliyD 19 уровень, Москва
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 Недостаточно денег
...
Дмитрий 18 уровень
22 февраля, 11:11
Сначала я решил, что раз тратят деньги 3 потока, а добавляет всего один, то синхронизировать нужно трату, но Валера сказал НЕТ - твоя логика не верна. Видимо потому что метод "deposit(BigDecimal money)" не атомарный, осуществляется в несколько этапов: создать переменную, получить текущее состояние банковского счета, увеличить его на значение "money", вывести на экран уведомление о том, что операция выполнена (хотя фактически это не так), присвоить переменной банковского счета новое значение. Мы как бы говорим потокам, тратящим бабло: парни погодите минуточку, не суетитесь, деньги начали поступать на счет)
Даниил Александрович 25 уровень, Тамбов
3 февраля, 06:20
разработчик который мутит много поточный банкомат надо на нобелевскую. работа со счетами в потоках в банке имеет ли смысл? у счета 1 бенифицар. это как файловая система. читать могут все, но как только приходит запрос на запись сразу накладывается lock. и все что проиходит четко только в порядке очереди.
Vladimir Shevchenko 22 уровень, Днепр
23 января, 06:21
Подскажите что это такое в классе банкомат, статический блок или что это???: private static Thread addMoney = new Thread() { ... };
Бельчонок Изи 23 уровень, Казань
23 января, 12:35
Я думаю, что это так называемый анонимный класс. Когда при создании объекта сразу прописывается реализация его метода.
Максим Дудин 20 уровень, Калининград
23 декабря 2020, 19:41
В идее, в исходном варианте, у меня задача работает исключительно корректно... видимо частный случай, поэтому и залез посмотреть комментарии дабы убедиться в чём подвох..
Булат 28 уровень, Москва
22 декабря 2020, 20:02
Не уверен, что правильно, но объяснил для себя так (после примитивного добавления модификаторов): Методы withdraw и deposit вызываются на объекте account
static BankAccount account = new BankAccount("Amigo");
Который является общим статическим для наших потоков. Т.е. добавили synchronized для методов - ака сказали, что метод синхронный на объекте this, т.е. account - лок. Поэтому (этот кусок инфа было непросто найти и переварить) при вхождении одного потока spendThread в sync метод withdraw (например) другие потоки spendThread2,3, etc. будут ожидать первый и не смогут вообще никакие другие sync блоки/методы этого объекта исполнять. Т.е. потоки теперь после установки модификаторов поочередно дергают объект на котором залочены его конкретные методы - в нашем случае аккаунт. Поправьте если не прав. P.S. Изначаль рассуждал, что если поточные переменные разные spendThread spendThread1 spendThread2, то и независимо все должно исполняться, но нет надо смотреть конкретно что за объект this на котором вызываются sync методы
Future Man 25 уровень
29 декабря 2020, 10:14
ну да кинул блок synhronized на account в run - результат тот же, что и если кинуть deposit и withdraw
Игорь HDL developer в Y
16 декабря 2020, 15:21
Задача показательная, хотя статичность банковского счета смущает. Концептуально данный банкомат работает с одним единственным счетом, это весьма странно.
Евгений 22 уровень, Новосибирск
6 декабря 2020, 02:55
Комрадос, а может кто-то просветить, что за синтаксис такой диковинный со стрелочкой? Вроде, раньше в задачах не попадался.
Паровозик, который смог 34 уровень, Москва
23 декабря 2020, 11:42
Надо нажать на нее, и она раскроется :) Просто "компактит" код в нечто меньшее по объёму.
9 января, 17:43
В каком-то смысле, конечно, "компактит" :)) Это "лямбда" - оч. популярная штука в Java. Просто мы до нее еще не дошли. Работает с функциональными интерфейсам - т.е. когда есть интерфейс с одной функцией. Соответсвенно имя функции можно скрыть - она и так известна. Вот классное видео на тему - Лямбда-выражения