2008-10-02 4 views
9

При разработке класса коллекции существует ли какая-либо причина не реализовывать блокировку в частном порядке, чтобы сделать ее потокобезопасной? Или я должен оставить эту ответственность до потребителя коллекции?Сделайте ваши коллекции потокобезопасными?

+1

Если вы сделаете свою коллекцию неизменной, она будет неотъемлемой частью потокобезопасной, без необходимости ее блокировки. – Juliet 2010-09-26 15:22:56

ответ

13

есть ли причина не реализовывать блокировку в частном порядке, чтобы обеспечить безопасность потока?

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

Решите проблемы, которые у вас есть. Не пытайтесь решать будущие проблемы, которые, по вашему мнению, могут иметь несколько лет в будущем, потому что вы не можете видеть будущее, и вы всегда будете неправы.

Примечание: вам все равно необходимо написать свой код удобным для использования способом, чтобы, если вы сделали, необходимо прийти и добавить блокировку в коллекцию, это было бы не очень сложно. Моя точка зрения заключается в том, что «не реализуйте функции, которые вам не нужны и не будут использовать»

+2

Не уверен, что я куплю это не будет ужасно сложно ", если вы обеспокоены многопоточной производительностью. Это легко сделать наивно, но трудно сделать хорошо. Пойдите взгляните на код ConcurrentHashMap против HashMap. – 2008-10-03 04:29:15

2

Я лично оставил его потребителям. Это сделает ваш коллекционный класс более универсальным.

10

Для Java вы должны оставить несинхронизированную скорость. Потребитель коллекции может обернуть по желанию synchronization wrapper.

2

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

0

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

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

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

2

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

Обратите внимание на «Если» в начале. Некоторые клиенты захотят этого, а некоторые - нет, а некоторым все равно. Если вы собираетесь создать набор инструментов для потребителей, то почему бы не предложить обе разновидности? Таким образом, я могу выбрать, какой из них использовать, но если я хочу потокобезопасность, у вас все еще есть мое внимание, и мне не нужно писать это самостоятельно.

3

Коллекционные классы должны быть как можно быстрее. Поэтому оставьте замки.

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

1

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

0

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

0

Если вы создаете класс коллекции, не делайте его потокобезопасным. Это довольно сложно сделать правильно (например, правильно и быстро), и проблемы для вашего потребителя, когда вы делаете это неправильно (heisenbugs), трудно отлаживать.

Вместо этого реализуйте один из API Collection Collection и используйте Collections.synchronizedCollection (yourCollectionInstance), чтобы получить потокобезопасную реализацию, если она в ней нуждается.

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

1

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

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

1

Создание коллекции threadsafe - это то, что убило классы Java и Hashtable. Клиенту гораздо проще обернуть его в потокобезопасную оболочку, как было предложено ранее, или синхронизировать доступ к данным по подмножеству методов, а не удалять синхронизацию каждый раз при обращении к классу. Вряд ли кто-то использует Vector или Hashtable, и если они это сделают, они смеются, потому что их замены (ArrayList и HashMap) быстрее миров. К сожалению, поскольку я (исходя из фона C++) предпочитаю имя «Вектор» (STL), но ArrayList остается здесь.

1

В принципе, создайте свою коллекцию как потокобезопасную, с блокировкой, реализованной в двух методах вашего класса: lock() и unlock(). Назовите их в любом месте, но оставьте их пустыми. Затем подкласс вашей коллекции реализует методы lock() и unlock(). Два класса по цене одного.

1

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

Настоящая повод сделать вашу коллекцию потокобезопасной для улучшения многопоточной производительности. Пример: ConcurrentHashMap поверх HashMap. Поскольку CHM использует многопоточные проблемы, он может блокировать блокировку для большего параллельного доступа более эффективно, чем внешняя синхронизация.

0

Вот хорошее начало.

thread-safe-dictionary

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

6

Взаимозависимые коллекции могут обманывать. Jared Par опубликовал пару интересных статей о коллекциях с резьбой:

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

...

Но если построения data thread safe список настолько прост, почему не Microsoft добавить эти стандартные коллекции в рамки ?

Ответ: ThreadSafeList является практически непригодным для класса, потому что дизайн ведет вас по пути к плохой кода.

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

static int GetFirstOrDefault(ThreadSafeList<int> list) { 
    if (list.Count > 0) { 
     return list[0]; 
    } 
    return 0; } 

Этот код является классическим состояние гонки. Рассмотрим случай, когда в списке есть только один элемент. Если другой поток удаляет этот элемент между оператором if и оператором return, оператор return генерирует исключение, потому что он пытается получить доступ к недопустимому индексу в списке. Несмотря на то, ThreadSafeList является поточно безопасность данных, нет ничего гарантировать справедливость возвращаемого значения одного вызова через следующий вызов на тот же объект

http://blogs.msdn.com/b/jaredpar/archive/2009/02/11/why-are-thread-safe-collections-so-hard.aspx

http://blogs.msdn.com/b/jaredpar/archive/2009/02/16/a-more-usable-thread-safe-collection.aspx

0

По версии JDK 5, если вам нужна потокобезопасная коллекция. Сначала я увижу, будет ли работать одна из уже реализованных коллекций в java.util.concurrent. Поскольку авторы Java Concurrency In Practice указывают (включая парня, написавшего большую часть классов), реализующего их правильно, очень сложно, особенно если производительность важна.

кавычки http://download.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html

Параллельное Коллекции

Кроме Очереди, этот пакет поставляет реализации Collection, предназначенные для использования в многопоточных контекстах: ConcurrentHashMap, ConcurrentSkipListMap, ConcurrentSkipListSet, CopyOnWriteArrayList, и CopyOnWriteArraySet.Когда много потоков , как ожидается, получить доступ к данным коллекции, ConcurrentHashMap является обычно предпочтительнее синхронизированной HashMap и ConcurrentSkipListMap , как правило, предпочтительнее синхронизированной TreeMap. A CopyOnWriteArrayList является предпочтительным для синхронизированным ArrayList, когда ожидаемое число считываний и обхода значительно превышают число обновлений для списка .

Смежные вопросы