Банкомат

  • 9
  • Недоступна
Разберись, как работает программа Во время тестирования лог содержит следующее: ..... Добавляем 100, на счету 1100 Добавляем 100, на счету 1200 Тратим 1000, на счету 100 Недостаточно денег ..... Создан баг: При списании денег со счета теряются деньги Найти и исправить ошибку
Вы не можете решать эту задачу, т.к. не залогинены.
Комментарии (78)
  • популярные
  • новые
  • старые
Для того, что бы оставить комментарий вы должны авторизоваться
Mikhail Uchakov18 уровень, Санкт-Петербург
вчера, 09:31
Валидатор принимает решение только при изменении двух методов в классе BankAccount. Читайте внимательно требования к задаче.
Игорь22 уровень, Нижний Новгород
31 декабря 2018, 09:20
Не понятно почему не срабатывает синхронизация внутри метода withdraw:
public void withdraw(BigDecimal money) throws NotEnoughMoneyException {
     synchronized (balance) {
          BigDecimal newBalance = balance.subtract(money);
          if (newBalance.compareTo(BigDecimal.ZERO) < 0) throw new NotEnoughMoneyException();
          balance = newBalance;
          System.out.println("Тратим " + money + ", на счету " + balance);
     }
}
В таком варианте есть возможность вывода:
Тратим 100, на счету 400
Тратим 100, на счету 200
Тратим 100, на счету 200
Тратим 100, на счету 100
Тратим 100, на счету 0
Хотя и изменение переменной и ее вывод внутри одного блока synchronized. Приходится синхронизировать на уровне всего объекта - т.е. добавлять synchronized в сигнатуру метода:
public synchronized void withdraw(BigDecimal money)
Хотя никак не понимаю почему в первом варианте может быть такой баг - ведь у нас все нити используют один объект BankAccount и в нем изменение переменной и ее вывод неразделимы.
Pavlic Morozov (pashok09i)20 уровень, Екатеринбург
16 декабря 2018, 19:47
очень странно, ничего не менял, программа работала корректно, менял и сумму добавления и списания. Синхронизация видимых результатов не дала...
Vitaly Khan35 уровень
1 декабря 2018, 08:06
уменьшил время сна в addMoney до 500 мс и... убедился, что синхронизация методов в BankAccount не помогает убрать глюки! периодически проскакивает "Недостаточно денег" там, где этого быть не должно! я пробовал все виды синхронизации в методах deposit и withdraw, пробовал помечать balance, как volatile. но ВО ВСЕХ СЛУЧАЯХ программа иногда давала сбои.... (валидатор-то с первой попытки был удовлетворен...) UPDATE: разгадку нашел сам, она в моем комментарии немного ниже.
Vitaly Khan35 уровень
1 декабря 2018, 09:47
думал, что разобрался как работает синхронизация... но на этой задачи столкнулся c чем-то необъяснимым пока. просьба к остальным. попробуйте поставить задержку 500 мс в addMoney и погоняйте программу много раз. не у меня же одного такая проблема?... (картинка прилагается)
Dinara20 уровень, Москва
2 декабря 2018, 16:23
Да, у меня так же... Получается, во время выполнения метода deposit(), когда поток addMoney уже успел вывести на печать новый баланс
System.out.println("Добавляем " + money + ", на счету " + newBalance);
, но до выполнения команды
balance = newBalance;
, выполнение переключается на один из потоков spendThread, а баланс еще не обновился. Предполагаю, что проблема в этом. Т.к. объявление переменной balance как volatile не помогло.
Vitaly Khan35 уровень
3 декабря 2018, 02:17
не совсем так, Динара! я пробовал делать еще один вывод на экран в методе deposit уже ПОСЛЕ balance = newBalance; и было видно, что этот вывод происходит, а значит, и баланс обновлен! и уже ПОСЛЕ ЭТОГО вываливалось сообщение от другого потока, что недостаточно денег!
Vitaly Khan35 уровень
3 декабря 2018, 02:45
а вот теперь я понял, из-за чего это происходит! один поток заходит в withdraw, когда баланс равен 0. доходит до проверки условия и делает throw new NotEnoughMoneyException(); в этот момент он выходит из блока synchronized и снимает блокировку! еще до того, как он успеет обработать в методе run исключение, другой поток заходит в deposit и успешно кладет деньги на счет. только после этого происходит обработка исключения первым потоком! уфф))) разгадал) остается синхронизировать снятие денег в методе run. хотя это настолько замедляет выполнение, что у меня банковский счет начинает только из-за блока synchronized пополняться быстрее, чем расходоваться (при задержке 500 мс в addMoney).
vk18 уровень, Санкт-Петербург
12 декабря 2018, 21:44
F! А почему нельзя сделать синхронизацию только снаружи - на вызов метода account.deposit и на весь блок try
{
    account.withdraw("100");             //снимаем со счета
} catch (NotEnoughMoneyException e) {
    System.out.println("Недостаточно денег");
}
и не настраивать синхронизацию внутри аккаунта?
Игорь22 уровень, Нижний Новгород
31 декабря 2018, 10:00
Попробовал синхронизацию только снаружи:
while (!isStopped) {
     synchronized (account) {
          account.deposit("1000");
               try {
                    Thread.sleep(1000);
               } catch (InterruptedException e) {
                    break;
          }
     }
}
Получил такой вот вывод:
Добавляем 1000, на счету 1000
Добавляем 1000, на счету 2000
Добавляем 1000, на счету 3000
Добавляем 1000, на счету 4000
Добавляем 1000, на счету 5000
Тратим 100, на счету 4900
Тратим 100, на счету 4800
Тратим 100, на счету 4700
Получается, что нити, ответственные за пополнение, даже не успевают войти в соответствующие методы. А если синхронизировать внутри, то они туда заходят, натыкаются на блокировку, но по освобождению объекта - продолжают выполнение своих методов.
Игорь22 уровень, Нижний Новгород
31 декабря 2018, 10:24
А, ошибся... не надо в deposit в synchronized try-sleep заворачивать. Тогда все работает.
fleek22 уровень
23 ноября 2018, 16:04
данный пример в помощь https://www.youtube.com/watch?v=FPN7gadNT4A&list=PLnV3K-pmuXwg9S6YhNnWvOG3PXkSaVPsN
Игорь23 уровень
4 ноября 2018, 19:31
почему если запускаем еще одну нить addMoney.start() выводится IllegalThreadStateException и тратильщики денег тоже не запускаются?
Anonymous #37410529 уровень, Амстердам
13 ноября 2018, 14:54
Потому что ты дважды пытаешься запустить одну и ту же нить, а не ещё одну.
Photograph Pro20 уровень, Киев
4 октября 2018, 17:51
это прям один в один задача из Head First тема синхронизация потоков=))
Александр Толкачёв22 уровень, Санкт-Петербург
7 сентября 2018, 19:22
Для тех, кто хочет сам разобраться в программе, и не понимает где ошибка в исходном коде, добавьте второй аналогичный поток на добавление денег, и все станет ясно
13 августа 2018, 11:02
Ребята разработчики, опишите задачу, цель подробнее и яснее, вообще не понятно, что вы хотите.
Anastasiia20 уровень
2 августа 2018, 06:09
интересно зачем в 33 строчке => ;
Роман Патрушев23 уровень, Казань
21 августа 2018, 12:44
здесь при создании объекта класса (безымянного) идет сразу объявление этого класса, наследуемого от Thread