Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Java [игнор отключен] [закрыт для гостей] / Задача с собеседования / 25 сообщений из 35, страница 1 из 2
11.11.2013, 22:02:23
    #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
11.11.2013, 22:18:34
    #38461146
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с собеседования
Честно говоря, не до конца понят как задача соотноситься к решению. Счет, ведь, обычно в одной валюте. А при использовании разных валют, банк продаёт\покупает по своему курсу. Ну, да ладно.
- Почему код валюты это security?
- Стоило использовать Checked Exception с явным содержанием деталей, например суммы. Unchecked Exception можно использовать для ошибок, которые мы не особо-то и ожидаем. Здесь же Exception часть логики. Конкретно его нужно будет снаружи ловить и обрабатывать.
- if (value < 0) { throw... реализовано копипастом. Причем именно этот кусок напрашивается на будущие изменения. Тот же овердрафт.
- Секции else { return; } я вообще не понял. Т.е. при определенном условии, мы тихо и тупо игнорируем трансфер. Клиент думает что деньги перевелись, а по факту - не совсем?
...
Рейтинг: 0 / 0
11.11.2013, 22:18:58
    #38461147
javapecker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с собеседования
mikhail_zh,security?
...
Рейтинг: 0 / 0
11.11.2013, 22:26:21
    #38461157
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с собеседования
Ещё у меня есть сомнения что Atomic здесь было резонно использовать. Если мы ожидаем неких пиковых нагрузок на один счет, то цикл, ведь может свалиться в starvation. А если не ожидаем, то, мне кажется, и разницы с synchronized особой не будет.
...
Рейтинг: 0 / 0
12.11.2013, 11:14:56
    #38461497
Andrew1411
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с собеседования
Blazkowicz- Секции else { return; } я вообще не понял. Т.е. при определенном условии, мы тихо и тупо игнорируем трансфер. Клиент думает что деньги перевелись, а по факту - не совсем?

Запутано в коде, но верно. Это ситуация удачного "первоначального взноса". При неудачном, идет пополнение.
...
Рейтинг: 0 / 0
12.11.2013, 11:21:41
    #38461506
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с собеседования
Andrew1411Запутано в коде, но верно. Это ситуация удачного "первоначального взноса". При неудачном, идет пополнение.
Ага, т.е. и сам трансфер у нас реализован в двух местах, двумя разными способами. Теперь понял. Спасибо.
...
Рейтинг: 0 / 0
12.11.2013, 12:03:00
    #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
12.11.2013, 12:11:27
    #38461598
Сергей Арсеньев
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с собеседования
А я бы согласился с Blazkowicz - и сделал synchronized -
ибо порядок операций списания-начисления денег IMHO тоже важен.
...
Рейтинг: 0 / 0
12.11.2013, 12:14:21
    #38461605
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с собеседования
Сергей АрсеньевА я бы согласился с Blazkowicz - и сделал synchronized -
ибо порядок операций списания-начисления денег IMHO тоже важен.
Дык synchronized тоже порядок не гарантирут. Для порядка нужно очередь добавить. Но в порядке имхо, нет особого смысла.
...
Рейтинг: 0 / 0
12.11.2013, 12:17:26
    #38461610
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с собеседования
А ещё, Atomic, все же наверно, быстрее чем synchronized в контексте большой системы с кучей счетов. Пиковой нагрузки в многие тысячи трансферов в секунду на один счет вряд ли можно ожидать.
...
Рейтинг: 0 / 0
12.11.2013, 12:19:18
    #38461613
Сергей Арсеньев
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с собеседования
BlazkowiczДык synchronized тоже порядок не гарантирут. Для порядка нужно очередь добавить. Но в порядке имхо, нет особого смысла.
1.Насчет очереди это еще вернее.
2. Люди попавшие на "технический овердрафт", наверное, с вами не согласятся.
...
Рейтинг: 0 / 0
12.11.2013, 12:21:53
    #38461618
Andrew1411
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с собеседования
Сергей Арсеньев,

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

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

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

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

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

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

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

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

тепеь смотрим на бизнеспроцесс.
1. Банк, открывает мультисчета в 3-х валютах, RUR, USD, EUR.
2. Через некоторое время, решает на правах публичной оферты (или как там правильно)? всем добавить возможность работы еше с 30 вакютами. итого, у каждого должно быть 33 остатка, при условии, что в 70% случаем используется не более 3-х валют? и болье 7 валют никтог не использует????
...
Рейтинг: 0 / 0
12.11.2013, 13:13:20
    #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
12.11.2013, 13:22:42
    #38461732
Сергей Арсеньев
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с собеседования
Сергей Арсеньев,

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

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


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


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