синхронизация чтения в коллекцию Java - PullRequest
8 голосов
/ 19 мая 2010

так что я хочу иметь 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 - одновременно я подхожу к этому правильно?

спасибо.

Ответы [ 6 ]

3 голосов
/ 19 мая 2010

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

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

1 голос
/ 19 мая 2010

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

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

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

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

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

1 голос
/ 19 мая 2010

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

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

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

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

1 голос
/ 19 мая 2010

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

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

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

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

1 голос
/ 19 мая 2010

Это выглядит как разумный подход. Тем не менее, вы не должны включать оператор 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 голос
/ 19 мая 2010

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

Collections.synchronizedList

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...