Java Collection Framework: Некоторые потокобезопасны, а некоторые нет?
Я изучаю фреймворк Java-коллекции (а не фреймворк Concurrent Collection) и узнал, что некоторые реализации Collection являются поточно-ориентированными, а некоторые - нет.
В большинстве материалов, которые я прочитал, все, что упоминается, что xyz
потокобезопасен и abc
не потокобезопасен.
Но какова логика, основанная на том, какое решение было принято, сохранять ли данный тип коллекции (например, List, Set, Queue, даже в Map..) потокобезопасным или нет?
Мой вопрос относится к "Традиционной" платформе Collection, а не к Concurrent Collection Framework.
Любые вклады в понимание этого были бы очень полезны.
3 ответа
Безопасность потоков несет накладные расходы (хотя в современных виртуальных машинах эти издержки значительно ниже, чем при разработке инфраструктуры сбора). Таким образом, коллекции не являются поточно-ориентированными, если это не требуется специально, за исключением коллекций JDK1.1 - когда они разрабатывались, философия была больше похожа на "давайте оставим немного места для ошибок ценой некоторой производительности".
У нас есть несколько этапов в развитии Java API.
JDK1.1
В версии 1.1 Java у нас были структуры данных Vector
а также Hashtable
, Они полностью синхронизированы, обеспечивая уровень безопасности потоков.
JDK1.2
В версии 1.2 Java была представлена структура коллекций. Ни одна из базовых коллекций не является поточно-ориентированной (они не синхронизируют никакие операции): ArrayList
, LinkedList
, HashMap
, TreeMap
и Set
Реализации.
Но вы можете получить синхронизированную версию, позвонив Collections.synchronizedMap
, Collections.synchronizedList
, так далее.
JDK1.5
В версии 1.5 Java java.util.concurrent
рамки были введены. Они содержат специализированные данные, структурированные для многопоточного использования. Они обеспечивают уровень безопасности потока.
Обратите внимание, что даже с синхронизированными коллекциями можно ввести гонки данных; это только означает, что вы не можете разрушить внутреннюю структуру коллекций (все инварианты коллекций будут сохранены)
Например, если у вас есть двухэтапный процесс, в котором вы сначала проверяете, что коллекция не содержит какого-либо элемента, а на втором этапе вы вставляете этот элемент. Если вы не предоставляете собственную синхронизацию для этих двух шагов, вы можете добавить элемент дважды, если два потока делают это одновременно.
Как утверждают другие, у одновременных коллекций есть время выполнения и потенциальная нагрузка на память, следовательно, разделение в поточно-безопасных и небезопасных коллекциях.
Большинство структур данных, которые вы можете найти в однопоточной библиотеке, имеют несколько поточно-ориентированных альтернатив. Одно заметное исключение List
Вероятно, потому, что в приложениях редко требуется одновременный список.
Для таких вещей, как очереди и стеки, у вас есть огромный выбор, потому что обычно производитель и один или несколько потребителей одновременно тянут и проталкивают очередь. Для реализации кеша вы можете положиться на карту, поэтому параллельные карты также хорошо поддерживаются.
Тот факт, что некоторые структуры данных на самом деле не были отражены в поточно-ориентированном API, просто объясняется тем, что они, как правило, не были бы полезны в многопоточном контексте.
Причины, скорее всего, связаны с производительностью. Синхронизация между несколькими потоками является дорогостоящей операцией, особенно с большой коллекцией элементов.