При разработке класса коллекции существует ли какая-либо причина не реализовывать блокировку в частном порядке, чтобы сделать ее потокобезопасной? Или я должен оставить эту ответственность до потребителя коллекции?Сделайте ваши коллекции потокобезопасными?
ответ
есть ли причина не реализовывать блокировку в частном порядке, чтобы обеспечить безопасность потока?
Это зависит. Ваша цель написать класс коллекции, к которому обращаются несколько потоков? Если это так, сделайте его потокобезопасным. Если нет, не тратьте свое время. Об этом говорят люди, когда говорят о «преждевременной оптимизации»
Решите проблемы, которые у вас есть. Не пытайтесь решать будущие проблемы, которые, по вашему мнению, могут иметь несколько лет в будущем, потому что вы не можете видеть будущее, и вы всегда будете неправы.
Примечание: вам все равно необходимо написать свой код удобным для использования способом, чтобы, если вы сделали, необходимо прийти и добавить блокировку в коллекцию, это было бы не очень сложно. Моя точка зрения заключается в том, что «не реализуйте функции, которые вам не нужны и не будут использовать»
Не уверен, что я куплю это не будет ужасно сложно ", если вы обеспокоены многопоточной производительностью. Это легко сделать наивно, но трудно сделать хорошо. Пойдите взгляните на код ConcurrentHashMap против HashMap. – 2008-10-03 04:29:15
Я лично оставил его потребителям. Это сделает ваш коллекционный класс более универсальным.
Для Java вы должны оставить несинхронизированную скорость. Потребитель коллекции может обернуть по желанию synchronization wrapper.
В вашей документации должно быть ясно, что вы не делаете его потокобезопасным и не оставляете его, или если для вашего приложения вы хотите, чтобы он был потокобезопасным, сделайте его потокобезопасным и обратите внимание, что в его документации для него. Единственное правило - документировать его. Помимо этого, сделайте свой класс для вас, и если другие люди захотят его использовать, они могут это сделать.
Это сделало бы невозможным одновременный доступ к коллекции из нескольких потоков, даже если вы знаете, что элемент, который вы касаетесь, не используется кем-либо еще.
Примером может служить коллекция с индексом доступа на основе целых чисел. Каждый поток может узнать из своего идентификатора, какие значения индекса он может получить, не беспокоясь о грязных чтениях/записи.
Другим случаем, когда вы получите ненужный удар производительности, будет то, что данные считываются только из коллекции и не записываются в.
Если я ищу класс коллекции, и мне нужны потокобезопасные возможности, и ваш класс их не имеет, я сразу же перейду к следующему предложению, чтобы увидеть, что они предоставляют. Ваша коллекция больше не привлечет мое внимание.
Обратите внимание на «Если» в начале. Некоторые клиенты захотят этого, а некоторые - нет, а некоторым все равно. Если вы собираетесь создать набор инструментов для потребителей, то почему бы не предложить обе разновидности? Таким образом, я могу выбрать, какой из них использовать, но если я хочу потокобезопасность, у вас все еще есть мое внимание, и мне не нужно писать это самостоятельно.
Коллекционные классы должны быть как можно быстрее. Поэтому оставьте замки.
Вызывающий код будет знать, где лучше всего блокирует класс коллекций. В худшем случае приложение должно будет добавить дополнительный замок, означающий, что два замка происходят, делая его двойным перфомансом.
Основная причина не в том, чтобы обеспечить безопасность потока - это производительность. Потоковый безопасный код может быть в 100 раз медленнее, чем не безопасный код, поэтому, если клиент не хочет эту функцию, это довольно большая трата.
Я согласен с тем, что оставить его потребителю - это правильный подход. Если пользователь предоставляет гораздо большую гибкость в отношении синхронизации экземпляра коллекции или синхронизации другого объекта. Например, если у вас было два списка, которые необходимо было обновить, может иметь смысл иметь их в одном синхронизированном блоке с использованием одной блокировки.
Если вы создаете класс коллекции, не делайте его потокобезопасным. Это довольно сложно сделать правильно (например, правильно и быстро), и проблемы для вашего потребителя, когда вы делаете это неправильно (heisenbugs), трудно отлаживать.
Вместо этого реализуйте один из API Collection Collection и используйте Collections.synchronizedCollection (yourCollectionInstance), чтобы получить потокобезопасную реализацию, если она в ней нуждается.
Просто обратитесь к соответствующим коллекциям.synchronizedXXX метод в вашем классе javadoc; он ясно укажет на то, что вы рассмотрели безопасность потоков в своем дизайне и обеспечили, чтобы потребитель располагал поточно-безопасным вариантом.
Обратите внимание, что если вы попытаетесь создать поточный сейф любого класса, вам необходимо будет решить общие сценарии использования.
Например, в случае коллекции просто все свойства и методы, индивидуально защищенные потоком, могут быть недостаточно хорошими для потребителя, поскольку чтение сначала счетчика, а затем цикл или подобное не будет очень хорошо, если счет изменился после прочтения.
Создание коллекции threadsafe - это то, что убило классы Java и Hashtable. Клиенту гораздо проще обернуть его в потокобезопасную оболочку, как было предложено ранее, или синхронизировать доступ к данным по подмножеству методов, а не удалять синхронизацию каждый раз при обращении к классу. Вряд ли кто-то использует Vector или Hashtable, и если они это сделают, они смеются, потому что их замены (ArrayList и HashMap) быстрее миров. К сожалению, поскольку я (исходя из фона C++) предпочитаю имя «Вектор» (STL), но ArrayList остается здесь.
В принципе, создайте свою коллекцию как потокобезопасную, с блокировкой, реализованной в двух методах вашего класса: lock() и unlock(). Назовите их в любом месте, но оставьте их пустыми. Затем подкласс вашей коллекции реализует методы lock() и unlock(). Два класса по цене одного.
Действительно хорошая причина НЕ сделать вашу коллекцию потокобезопасной для улучшения однопоточной производительности. Пример: ArrayList над вектором. Отключение защиты от потоков для вызывающего абонента позволяет избежать несинхронизированного варианта использования, избегая блокировки.
Настоящая повод сделать вашу коллекцию потокобезопасной для улучшения многопоточной производительности. Пример: ConcurrentHashMap поверх HashMap. Поскольку CHM использует многопоточные проблемы, он может блокировать блокировку для большего параллельного доступа более эффективно, чем внешняя синхронизация.
Вот хорошее начало.
Но вы заметите, вы потеряете одну из главных особенностей коллекции - перечисления. Вы не можете потокобезопасно перечислить, это просто не реально, если вы не реализуете свой собственный счетчик, который хранит блокировку экземпляра непосредственно в самой коллекции. Я бы заподозрил, что это вызовет серьезные узкие места и потенциальные тупики.
Взаимозависимые коллекции могут обманывать. 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
По версии 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, когда ожидаемое число считываний и обхода значительно превышают число обновлений для списка .
Если вы сделаете свою коллекцию неизменной, она будет неотъемлемой частью потокобезопасной, без необходимости ее блокировки. – Juliet 2010-09-26 15:22:56