Какие все коллекции Java синхронизированы и не синхронизированы

Какие все коллекции Java синхронизированы и не синхронизированы

Пример: HashSet не синхронизирован

11 ответов

Коллекции безопасных ниток -

  1. ConcurrentHashMap

Потокобезопасен без синхронизации всей карты. Очень быстрое чтение, в то время как запись выполняется с блокировкой. Нет блокировки на уровне объекта. Использует множество блокировок.

  1. SynchronizedHashMap

Синхронизация на уровне объекта. И чтение, и запись получают блокировку. Блокировка коллекции имеет недостаток производительности. Может вызвать конфликт

  1. Вектор

  2. Хеш-таблица

  3. CopyOnWriteArrayList

  4. CopyOnWriteArraySet

  5. стек

Все остальное не безопасно

Есть три группы коллекций.

  • Java 1.0 коллекции, которые в основном унаследованные классы. Это включает в себя Hashtable, Vector, Stack. Они синхронизированы, но я не рекомендую их использовать. Свойства, пожалуй, одно исключение, но я бы не стал использовать его в многопоточном контексте.
  • Коллекции Java 1.2, добавленные в 1998 году, которые в значительной степени заменили эти коллекции, не синхронизированы, но могут быть синхронизированы с помощью Collections.synchronizedXxx() методы
  • Коллекции параллелизма Java 5.0, добавленные в 2004 году, поддерживают коллекции без блокировок, безопасные для потоков.

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

Вы можете получить синхронизированную версию Java Collection с

Collections.synchronizedCollection(Collection<T> c)

[ Javadoc]

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

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

Информация всегда включена в javadoc ( как здесь: Arraylist - который не является потокобезопасным)

ArrayList, LinkedList, HashSet,LinkedHashset и TreeSet в интерфейсе коллекции, а также HashMap,LinkedHashMap и Treemap не синхронизированы.

Вектор в интерфейсе коллекции синхронизирован

  • Наследие - Vector(родитель List) и Hashtable(родитель Map)
  • Синхронизированные коллекции используют synchronized монитор. Collections.synchronized, Collections.synchronizedList(), Collections.synchronizedSortedMap(), Collections.synchronizedSet()...
  • Параллельные коллекции (Java 5)
    • Copy-On-Write(COW)- имеет лучшую производительность, чем синхронизированные коллекции, но требует большего объема памяти. Новая копия массива создается при его изменении (добавлении, установке, удалении). Это хороший вариант для операций многократного чтения и модификации задней части. CopyOnWriteArrayList, CopyOnWriteArraySet
    • Compare-And-Swap(CAS) <sup>[О]</sup> - ConcurrentLinkedQueue, ConcurrentSkipListMap
    • Lock основан - ConcurrentHashMap, BlockingQueue потомки

Все классы коллекций (кроме Vector и Hashtable) в пакете java.util не являются поточно-ориентированными. Только две старые коллекции являются поточно-ориентированными: Vector и Hashtable. ЗАЧЕМ? Вот причина: синхронизация может быть очень дорогой! Вы знаете, Vector и Hashtable - это две коллекции, которые существуют на ранних этапах истории Java, и они с самого начала разработаны для поточной защиты (если у вас есть возможность взглянуть на их исходный код, вы увидите, что все их методы синхронизированы!). Однако они быстро показывают низкую производительность в многопоточных программах. Как вы, возможно, знаете, синхронизация требует блокировок, для мониторинга которых всегда требуется время, что снижает производительность. Вот почему новые коллекции (List, Set, Map и т. Д.) Вообще не обеспечивают управление параллелизмом, чтобы обеспечить максимальную производительность в однопоточных приложениях.

Предыдущий пример совершенно неверен.

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

class ProcessSomething {
    private List<Integer> integerList = Collections.synchronizedList(new ArrayList<>());
    private void calculate() {
        for (int i = 0; i < 10000; i++) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException ex) {
                Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
            }
            integerList.add(new Random().nextInt(100));
        }
    }
    private void calculate2() {
        for (int i = 0; i < 10000; i++) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException ex) {
                Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
            }
            integerList.add(new Random().nextInt(100));
        }
    }
    public void process() {
        Long start = System.currentTimeMillis();
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                calculate();
            }
        });
        t1.start();
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                calculate2();
            }
        });
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException ex) {
            Logger.getLogger(ProcessSomething.class.getName()).log(Level.SEVERE, null, ex);
        }
        Long end = System.currentTimeMillis();
        System.out.println("Duration: " + (end - start));
        System.out.println("List size: " + integerList.size());
    }
}
public class App {
    public static void main(String[] args) {
        new ProcessSomething().process();
    }
}

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

for example:


    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Iterator;
    import java.util.List;

    public class SynchronizedListExample {

        public static void main(String[] args) {

            List<String> syncList = Collections.synchronizedList(new ArrayList<String>());

            syncList.add("one");//no need to synchronize here
            syncList.add("two");
            syncList.add("three");
            String st = syncList.get(0); //it is ok here => no need to synchronize

            // when iterating over a synchronized list, we need to synchronize access to the synchronized list
           //because if you don't synchronize here, synchList maybe be changed during iterating over it
            synchronized (syncList) {
                Iterator<String> iterator = syncList.iterator();
                while (iterator.hasNext()) {
                    System.out.println("item: " + iterator.next());
                }
            }

        }

    }

Import java.util.Collections; // Импортируем это

List<String> syncList = Collections.synchronizedList(new ArrayList<String>());

Вот как вы можете синхронизировать список в java.

Я предполагаю, что каждая реализация API коллекции написана в документации.

Другие вопросы по тегам