powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Задача с собеседования
25 сообщений из 35, страница 1 из 2
Задача с собеседования
    #38461135
mikhail_zh
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сабж: Нужно реализовать банковский счет. Т.е. на него можно переводить или снимать деньги в различных валютах. Многопоточно естественно.

пример:
Код: java
1.
2.
3.
account.transfer("USD", 100) // зачислить 100
account.transfer("USD", -30) // снять 30, остаток 70
account.transfer("EUR", -10) // ошибка, в минус нельзя



Вот моя релизация, просьба ее попинать:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
public class Account { 
    ConcurrentMap<String, AtomicLong> positions = new ConcurrentHashMap<String, AtomicLong>();

    public void transfer(String security, int value) { 
        AtomicLong positionValue = positions.get(security); 
        if (positionValue == null) { 
            if (value < 0) { 
                throw new IllegalArgumentException(); 
            } 
            positionValue = new AtomicLong(value); 
            AtomicLong currentValue = positions.putIfAbsent(security, positionValue); 
            if (currentValue != null) { 
                positionValue = currentValue; 
            } else { 
                return; 
            } 
        } 
        long oldValue, newValue; 
        do { 
            oldValue = positionValue.get(); 
            newValue = oldValue + value; 
            if (newValue < 0) { 
                throw new IllegalArgumentException(); 
            } 
        } while (!positionValue.compareAndSet(oldValue, newValue)); 
    } 
}



У меня есть первый вопрос. Нужно ли тут пихать BigInteger или же переполнения лонга не страшны?
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461146
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Честно говоря, не до конца понят как задача соотноситься к решению. Счет, ведь, обычно в одной валюте. А при использовании разных валют, банк продаёт\покупает по своему курсу. Ну, да ладно.
- Почему код валюты это security?
- Стоило использовать Checked Exception с явным содержанием деталей, например суммы. Unchecked Exception можно использовать для ошибок, которые мы не особо-то и ожидаем. Здесь же Exception часть логики. Конкретно его нужно будет снаружи ловить и обрабатывать.
- if (value < 0) { throw... реализовано копипастом. Причем именно этот кусок напрашивается на будущие изменения. Тот же овердрафт.
- Секции else { return; } я вообще не понял. Т.е. при определенном условии, мы тихо и тупо игнорируем трансфер. Клиент думает что деньги перевелись, а по факту - не совсем?
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461147
javapecker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mikhail_zh,security?
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461157
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ещё у меня есть сомнения что Atomic здесь было резонно использовать. Если мы ожидаем неких пиковых нагрузок на один счет, то цикл, ведь может свалиться в starvation. А если не ожидаем, то, мне кажется, и разницы с synchronized особой не будет.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461497
Andrew1411
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz- Секции else { return; } я вообще не понял. Т.е. при определенном условии, мы тихо и тупо игнорируем трансфер. Клиент думает что деньги перевелись, а по факту - не совсем?

Запутано в коде, но верно. Это ситуация удачного "первоначального взноса". При неудачном, идет пополнение.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461506
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrew1411Запутано в коде, но верно. Это ситуация удачного "первоначального взноса". При неудачном, идет пополнение.
Ага, т.е. и сам трансфер у нас реализован в двух местах, двумя разными способами. Теперь понял. Спасибо.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461578
Andrew1411
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
для такого мультивалютного счета, я бы лучше написал такой код (беглый рефакторинг)

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
public class Account { 
    ConcurrentMap<String, AtomicLong> currencyBallance = new ConcurrentHashMap<String, AtomicLong>();

    public void transfer(String currency, int value) {
        AtomicLong currencyValue = getPrevCurrencyBalance(currency); 
         
        long oldValue, newValue; 
        do { 
            oldValue = currencyValue.get(); 
            newValue = oldValue + value; 
            if (newValue < 0) { 
                throw new IllegalArgumentException(); 
            } 
        } while (!currencyValue.compareAndSet(oldValue, newValue)); 
    } 
    
    private AtomicLong getPrevCurrencyBalance(String currency){
    	if(currencyBallance.get(currency) == null)
    		currencyBallance.putIfAbsent(currency, new AtomicLong(0));
    	return currencyBallance.get(currency);
    }
}



Плюс в том, что изменение баланса идет исключительно в одном месте.
getPrevCurrencyBalance выдает предыдущий баланс мультивалютного счета в разрезе переданной валюты. Если баланс по этой валюте не был инициализирован - инициализируется 0;
Минус - если первоначалка отрицательная, мы напрасно инициализируем остаток. Если он недопустим - то в метод getPrevCurrencyBalance протягиваем сумму..., но на мой взляд это лишнее.

по поводу исключения. IllegalArgumentException вам тут не подходит, поскольку исключение - явное нарушение бизнеслогики. Следовательно нужно создать свое исключение, причем проверяемое.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461598
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А я бы согласился с Blazkowicz - и сделал synchronized -
ибо порядок операций списания-начисления денег IMHO тоже важен.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461605
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей АрсеньевА я бы согласился с Blazkowicz - и сделал synchronized -
ибо порядок операций списания-начисления денег IMHO тоже важен.
Дык synchronized тоже порядок не гарантирут. Для порядка нужно очередь добавить. Но в порядке имхо, нет особого смысла.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461610
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А ещё, Atomic, все же наверно, быстрее чем synchronized в контексте большой системы с кучей счетов. Пиковой нагрузки в многие тысячи трансферов в секунду на один счет вряд ли можно ожидать.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461613
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczДык synchronized тоже порядок не гарантирут. Для порядка нужно очередь добавить. Но в порядке имхо, нет особого смысла.
1.Насчет очереди это еще вернее.
2. Люди попавшие на "технический овердрафт", наверное, с вами не согласятся.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461618
Andrew1411
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев,

Если дальше подумать о стратегии отложенных поручений по счету (когда поручение стремиться выполниться в течении определенного времени) - порядок становится вообще бредовой идеей.
Объединение в единую транзакцию нескольких операций по счету очередью не добиться, кроме того, в нутри одной бизнес транзакции, порядок тоже не всегда важен.
Транзакционностью операций в этом коде не пахнет, в задании тоже нет упоминания.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461621
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczА ещё, Atomic, все же наверно, быстрее чем synchronized

Тут не только Atomic, но еще и ConcurentMap. Так что может и не быстрее - надо проверить.
Особенно если ее заменить массивом, а строку - enum.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461622
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев 2. Люди попавшие на "технический овердрафт", наверное, с вами не согласятся.
Я не вижу тут причин для технического овердрафта. Недостаточно денег, проходит первый платеж, на который хватает.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461623
Andrew1411
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
[quot Сергей Арсеньев]Blazkowicz 2. Люди попавшие на "технический овердрафт", наверное, с вами не согласятся.

В этом коде нет возможности уйти в овердрафт.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461633
Andrew1411
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей АрсеньевBlazkowiczА ещё, Atomic, все же наверно, быстрее чем synchronized

Тут не только Atomic, но еще и ConcurentMap. Так что может и не быстрее - надо проверить.
Особенно если ее заменить массивом, а строку - enum.

Соглачен, ConcurentMap стоит заменить на простой мап, обложив правильной блокировкой. так как первоначальный взнос будет происходить существенно реже взятия существующего остатка и пополнений.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461635
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrew1411,

его вообще можно инициализировать при создании счета.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461641
Andrew1411
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mikhail_zhУ меня есть первый вопрос. Нужно ли тут пихать BigInteger или же переполнения лонга не страшны?

Если реч о госдолге США - надо переходить на BigInteger однозначно.
Если без стеба - максимальные/минимальные значения должны быть указанны в ТЗ.
Кроме того, пока у вас проблемы с центами, копейками и т.д.
Кроме того, не у всех стран минимальная платежная единица равна 0,01 единицы валюты, бывают и меньше (0,001 к примеру)
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461652
Andrew1411
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей АрсеньевAndrew1411,

его вообще можно инициализировать при создании счета.

тепеь смотрим на бизнеспроцесс.
1. Банк, открывает мультисчета в 3-х валютах, RUR, USD, EUR.
2. Через некоторое время, решает на правах публичной оферты (или как там правильно)? всем добавить возможность работы еше с 30 вакютами. итого, у каждого должно быть 33 остатка, при условии, что в 70% случаем используется не более 3-х валют? и болье 7 валют никтог не использует????
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461717
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrew14112. Через некоторое время, решает на правах публичной оферты (или как там правильно)? всем добавить возможность работы еше с 30 вакютами. итого, у каждого должно быть 33 остатка, при условии, что в 70% случаем используется не более 3-х валют? и болье 7 валют никтог не использует????
Массив на 30 элементов против Map.
Производительность первого будет малость выше с учетом, что первый раз кладут деньги один раз, а потом оперируют с ней чаще.
Но в любом случае с проинициализированной стуктурой - на каждую операцию получается всего 1 get и 1 compareAndSet из AtomicReference (на каждый тур борьбы с конкурентами)
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
public void transfer(final String cur,final double delta) {
     AtomicReference<BigDecimal> val = positions.get(cur);
     while (true) {
      BigDecimal old = val.get();
      BigDecimal newVal = old.add(new BigDecimal(delta)); -- если инициализировать null то проверку
      if (newVal.signum()<0) {
       throw new IllegalArgumentException();
      }
      if (val.compareAndSet(old,newVal)) return;
     }  
   }
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461732
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев,

И более того - если positions.get(cur) вернула null - надо шарашить exception - такая валюта не разрешена на данном счете. :)
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461733
Andrew1411
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев,

1. сопоставление ISO кода валюты и позиции в массиве как осуществлять?
2. явная, причем чрезмерная избыточность использования памяти в нагруженных системах - повод для рассмотрения проф-пригодности.
3. Все приватные вещи - должны рефакториться при оптимизациях в первую очередь, но создавать абсолютно в пустую объекты - редко бывает оптимальным, как в результате оптимизации, так и при преждевременной оптимизации.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461737
Andrew1411
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
проверка допустимых валют для счета - это обращение к бизнесметодам за метоинформацией. Не стоит метаинформацию интегрировать в сущность.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461771
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrew1411проверка допустимых валют для счета - это обращение к бизнесметодам за метоинформацией.
И делать это следует через Enterprise Bus, которая найдет нужный webservice ...
И в этот момент станет ясно, что оптимизация по производительности или по памяти, вообще, не роляет.


P.S. Можно конечно позанудствовать про ООП с возможностью сделать абстрактный счет и потомков (на одну валюту, на три и на много) с методами конвертации. Но не буду. Вы правы.
...
Рейтинг: 0 / 0
Задача с собеседования
    #38461776
Andrew1411
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Прикольно, что тестовая задачка вызвала обсуждение бизнеслогики. Прикольно потому, что, в такой постановке задачи бизнеслогика практически отсутствует.
Если вспомнить бухгалтерию (хоть предприятий, хоть баковскую), то сразу становится понятно, что сумма по счету сама по себе практически никогда не изменяется. Изменение проходит, в большинстве случаев, у двух счетов. Инициируется изменение проводкой.
При совершении проводки, должны измениться балансы у всех счетов, входящих в нее, либо остаться прежними у всех.
Соответственно, без механизмов транзакционности, задача не решаема.
Вводя транзакционность, можно опираться либо на "тотальные" блокировки (не позволять конкурирующей транзакции что то делать, пока не завершилась предыдущая), либо подходить более по умному - все незавершенные транзакции, должны участвовать в минимально- и максимально- возможной сумме по счету в случае удачного завершения любых из сущесвующих транзакций. Соответсвенно, транзакция должна анализировать, возможно ли ее гарантированное выполнение с учетом ожидающих транзакций, либо надо отваливаться сразу (или становиться в очередь отложенных транзакций).
Задача на столько тестовая, что в ней даже не присутствует упоминание типа счета (активный/пассивный), из-за которого зависит "знак" допустимого остатка (дебитовый/кредитовый).
...
Рейтинг: 0 / 0
25 сообщений из 35, страница 1 из 2
Форумы / Java [игнор отключен] [закрыт для гостей] / Задача с собеседования
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]