Сейчас писал функцию для сервера приложения и убил очень много времени на поиск ошибки. Вопрос из разряда "почему", а не как исправить, хочу понять в чем же проблема...
Программа делала следующее:
Водитель
.Для этого был один метод (синхронизированный блок, чтобы сразу все пользователи не меняли значение водителю, потом переделаю; код с БД вырезал):
public synchronized void setDriverLimit(int driverId, double driverLimit) {
mDriversMap.get(driverId).setMaxMoneyPerDay(new BigDecimal(driverLimit));
mDriversBroadcast.onDriverAction(ActionWrapper.builder()
.action(ActionWrapper.Action.CHANGED)
.object(mDriversMap.get(driverId))
.build());
}
После его вызова в сокет сервера записывался объект с новым значением (лимитом), за это отвечал метод onDriverAction
, а на выходе у клиента почему-то появлялся объект, который был ДО вызова метода (который был в Map
до того, как установился новый лимит). 6 часов ломал голову над проблемой, расставил везде логи - все работает правильно, но значения приходят не те... В сокет записывается объект с значением, скажем, 10, а приходит - 5! P.S. Я юыл очень удивлен и даже полез искать, нет ли такого глюка у OpenJDK, хотя и знал, что косяк мой... :))
В конце концов, решил посмотреть на аналогичные методы в том же классе и понял, что этот - единственный, который использует объекты из Map
, а не новосозданные. Написал так:
public synchronized void setDriverLimit(int driverId, double driverLimit) throws SQLException {
Driver driverWithNewLimit = Driver.builder()
.autogeneratedIdNotUse(mDriversMap.get(driverId).getAutogeneratedIdNotUse())
.driverId(driverId)
.driverName(mDriversMap.get(driverId).getDriverName())
.carNumber(mDriversMap.get(driverId).getCarNumber())
.driverPhoneNumber(mDriversMap.get(driverId).getCarNumber())
.driverPassword(mDriversMap.get(driverId).getDriverPassword())
.maxMoneyPerDay(new BigDecimal(driverLimit))
.lastToday(new BigDecimal(mDriversMap.get(driverId).getLastToday().doubleValue()))
.build();
mDriversMap.replace(driverId, driverWithNewLimit);
mDriversBroadcast.onDriverAction(ActionWrapper.builder()
.action(ActionWrapper.Action.CHANGED)
.object(driverWithNewLimit)
.build());
}
На удивление все заработало! Смысл написания такого метода заключался в избежании всевозможных ссылок на старые объекты.
Забыл упомянуть, что в сокет все записывалось самым простым образом: брался OutputStream
, преобразовывался в ObjectOutputStream
и туда записывались массивы ActionWrapper
методом writeObject()
. Массивы, а не одиночные объекты, потому что они собирались каждые 5 секунд и отправлялись группой.
Вопрос: а из-за чего такое поведение? Где это потокобезопасная HashMap
умудряется хранить ссылки или чего сокет обращается к старым ссылкам? Или, может, проблема в BigDecimal
? В общем, надеюсь, что человек, который в этом разбирается сможет расписать в чем же дело :).
Виртуальный выделенный сервер (VDS) становится отличным выбором
нужна программа которая считает размер папки и напечатать результат по 1 секунду
Двигаю ImageView с помощью ImageViewanimate()
Пытаюсь загрузить изображение в Bitmap таким способом
Ребята Знаю вопросы такого формата не очень тут )Но всеже решилсяНужно спроектировать приложение котьорое на камере отлавливает движение...