Поиск…


Вступление

Параллельная коллекция представляет собой [сборник] [1], который позволяет одновременно получать доступ к нескольким потокам. Различные потоки обычно могут проходить через содержимое коллекции и добавлять или удалять элементы. Сбор несет ответственность за то, чтобы сбор не стал коррумпированным. [1]: http://stackoverflow.com/documentation/java/90/collections#t=201612221936497298484

Тематические коллекции

По умолчанию различные типы коллекций не являются потокобезопасными.

Тем не менее, сделать коллекцию поточно-безопасной довольно простой.

List<String> threadSafeList = Collections.synchronizedList(new ArrayList<String>());
Set<String> threadSafeSet = Collections.synchronizedSet(new HashSet<String>());
Map<String, String> threadSafeMap = Collections.synchronizedMap(new HashMap<String, String>());

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

Java SE 5

Начиная с Java 5, у java.util.collections есть несколько новых потокобезопасных коллекций, которым не нужны различные методы Collections.synchronized .

List<String> threadSafeList = new CopyOnWriteArrayList<String>();
Set<String> threadSafeSet = new ConcurrentHashSet<String>();
Map<String, String> threadSafeMap = new ConcurrentHashMap<String, String>();

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

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

Хотя в потокобезопасных коллекциях есть безопасное добавление или удаление элементов из нескольких потоков, они не обязательно имеют безопасную итерацию в одном и том же контексте (возможно, не удастся выполнить итерацию через коллекцию в одном потоке, в то время как другая изменяет ее путем добавления / удаление элементов).

Здесь используются параллельные коллекции.

Поскольку итерация часто является базовой реализацией нескольких массовых методов в коллекциях, таких как addAll , removeAll , а также копирование коллекции (через конструктор или другие средства), сортировка, ... пример использования для параллельных коллекций на самом деле довольно большой.

Например, Java SE 5 java.util.concurrent.CopyOnWriteArrayList - это поточно-безопасная и параллельная реализация Lis t, ее javadoc заявляет:

Метод итератора стиля «моментальный снимок» использует ссылку на состояние массива в точке, в которой был создан итератор. Этот массив никогда не изменяется в течение жизни итератора, поэтому помехи невозможны, и итератору гарантировано не бросать ConcurrentModificationException.

Поэтому следующий код безопасен:

public class ThreadSafeAndConcurrent {

public static final List<Integer> LIST = new CopyOnWriteArrayList<>();

public static void main(String[] args) throws InterruptedException {
    Thread modifier = new Thread(new ModifierRunnable());
    Thread iterator = new Thread(new IteratorRunnable());
    modifier.start();
    iterator.start();
    modifier.join();
    iterator.join();
}

public static final class ModifierRunnable implements Runnable {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 50000; i++) {
                LIST.add(i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public static final class IteratorRunnable implements Runnable {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10000; i++) {
                long total = 0;
                for(Integer inList : LIST) {
                    total += inList;
                }
                System.out.println(total);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
}

Другая параллельная коллекция, посвященная итерации, - ConcurrentLinkedQueue , которая гласит:

Итераторы слабо согласованы, возвращая элементы, отражающие состояние очереди, в какой-то момент или после создания итератора. Они не бросают java.util.ConcurrentModificationException и могут продолжаться одновременно с другими операциями. Элементы, содержащиеся в очереди с момента создания итератора, будут возвращены ровно один раз.

Нужно проверить javadocs, чтобы увидеть, является ли коллекция параллельной или нет. Атрибуты итератора, возвращаемые методом iterator() («fail fast», «слабо согласованный», ...), являются наиболее важным атрибутом для поиска.

Потоковые, но не параллельные примеры

В приведенном выше коде, изменяя объявление LIST

public static final List<Integer> LIST = Collections.synchronizedList(new ArrayList<>());

Может (и статистически будет на большинстве современных многопроцессорных / основных архитектур) приведет к исключениям.

Синхронизированные коллекции из методов утилиты Collections являются потокобезопасными для добавления / удаления элементов, но не для итерации (если базовая коллекция не передается ей уже).

Вставка в ConcurrentHashMap

public class InsertIntoConcurrentHashMap
{

    public static void main(String[] args)
    {
        ConcurrentHashMap<Integer, SomeObject> concurrentHashMap = new ConcurrentHashMap<>();

        SomeObject value = new SomeObject();
        Integer key = 1;

        SomeObject previousValue = concurrentHashMap.putIfAbsent(1, value);
        if (previousValue != null)
        {
            //Then some other value was mapped to key = 1. 'value' that was passed to
            //putIfAbsent method is NOT inserted, hence, any other thread which calls
            //concurrentHashMap.get(1) would NOT receive a reference to the 'value'  
            //that your thread attempted to insert. Decide how you wish to handle             
            //this situation.
        }

       else
       {
            //'value' reference is mapped to key = 1.
       }
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow