синхронизация чтений к набору Java

таким образом, я хочу иметь arraylist, который хранит серию биржевых цен. но я отслеживаю цену предложения, запрашиваемую цену и последнюю цену для каждого.

конечно, в любое время, предложение спрашивают, или последний из данного запаса может измениться.

у меня есть один поток, который обновляет цены и ту, которая читает их.

я хочу удостовериться, что, не читая никакой другой поток обновляет цену. таким образом, я посмотрел на синхронизируемый набор. но это, кажется, только предотвращает чтение, в то время как другой поток добавляет или удаляет запись в arraylist.

таким образом, теперь я на подход обертки:

public class Qte_List {
private final ArrayList<Qte> the_list;

public void UpdateBid(String p_sym, double p_bid){
    synchronized (the_list){
        Qte q = Qte.FindBySym(the_list, p_sym);
        q.bid=p_bid;}
}

public double ReadBid(String p_sym){
    synchronized (the_list){
        Qte q = Qte.FindBySym(the_list, p_sym);
        return q.bid;}
}

таким образом, то, что я хочу выполнить с этим, является только одним потоком, может делать что-либо - чтение или обновление содержания the_list - когда-то. я, приближаются к этому праву?

спасибо.

8
задан jeff 19 May 2010 в 06:07
поделиться

6 ответов

Насколько я понимаю, вы используете карту для хранения котировок; количество котировок никогда не меняется, но каждую котировку можно прочитать или изменить, чтобы отразить текущие цены. Важно знать, что блокировка коллекции защищает только от изменений, для которых объекты Quote находятся на карте: она никоим образом не ограничивает модификацию содержимого этих Quotes. Если вы хотите ограничить этот доступ, вам нужно будет заблокировать объект Quote.

Однако, глядя на ваш код, я не думаю, что у вас есть серьезная проблема с синхронизацией. Если вы попытаетесь выполнить чтение одновременно с записью, вы получите либо цену до, либо цену после записи. Если вы не знали, что произойдет запись, это не имеет для вас значения. Вам может потребоваться блокировка на более высоком уровне, чтобы

if (getBidPrice(mystock)<10.0) {
  sell(10000);
}

выполнялась как атомарная операция, и вы не продавали по 5.0, а не по 10.0.

Если количество кавычек действительно не меняется, я бы рекомендовал разрешить добавление объектов Qte только в конструктор Qte_List. Это сделало бы блокировку коллекции неуместной. Технический термин для этого - сделать Qte_List неизменяемым .

1
ответ дан 5 December 2019 в 20:14
поделиться

Да, вы на правильном пути, и это должно сработать.

Но почему бы не использовать существующую коллекцию Hashtable , которая синхронизирована и уже обеспечивает поиск значения ключа?

3
ответ дан 5 December 2019 в 20:14
поделиться

Это похоже на разумный подход. Тем не менее, вы, вероятно, не должны включать оператор return в синхронизированный блок:

public double ReadBid(String p_sym){
    double bid;
    synchronized (the_list) {
        Qte q = Qte.FindBySym(the_list, p_sym);
        bid = q.bid;
    }

    return bid;
}

Я не уверен, что это просто мой вкус или здесь есть какие-то проблемы с параллелизмом, но, по крайней мере, мне это кажется более понятным ;-).

1
ответ дан 5 December 2019 в 20:14
поделиться

Да, это сработает, в любом случае вам не нужно делать это самостоятельно, поскольку это уже реализовано в структуре коллекций

Collections.synchronizedList

1
ответ дан 5 December 2019 в 20:14
поделиться

То, что у вас есть, будет работать, но блокировка всего списка каждый раз, когда вы хотите прочитать или обновить значение элемента, не масштабируется. Если это не имеет значения, значит, у вас все в порядке с тем, что у вас есть. Если вы хотите сделать его более масштабируемым, рассмотрите следующее ...

Вы не сказали, нужно ли вам иметь возможность вносить структурные изменения в the_list (добавляя или удаляя элементы), но если вы этого не сделаете, один большой улучшением будет перемещение вызова FindBySym () за пределы синхронизированного блока. Затем вместо синхронизации по the_list вы можете просто синхронизировать по q (объект Qte). Таким образом вы можете одновременно обновлять разные объекты Qte. Кроме того, если вы можете сделать объекты Qte неизменяемыми, вам вообще не нужна никакая синхронизация. (для обновления просто используйте the_list [i] = new Qte (...)).

Если вам действительно нужно иметь возможность вносить структурные изменения в список, вы можете использовать ReentrantReadWriteLock, чтобы разрешить одновременное чтение и исключительную запись.

Мне также любопытно, почему вы хотите использовать ArrayList, а не синхронизированную HashMap.

1
ответ дан 5 December 2019 в 20:14
поделиться

Ваш подход должен помочь, но, как вы сказали, одновременно может быть только один читатель и писатель. Это не очень масштабируемо.

Здесь есть несколько способов улучшить производительность без потери безопасности потоков.
Например, вы можете использовать ReadWriteLock . Это позволит нескольким читателям одновременно, но когда кто-то получает блокировку записи, все остальные должны ждать, пока он закончит.

Другой способ - использовать правильную коллекцию. Кажется, вы могли бы заменить свой список потокобезопасной реализацией Map . Взгляните на документацию ConcurrentMap для поиска возможных кандидатов.

Изменить:
Предполагая, что вам нужно упорядочить карту, взгляните на интерфейс ConcurrentNavigableMap .

1
ответ дан 5 December 2019 в 20:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: