Recherche…


Introduction

Une collection concurrente est une [collection] [1] qui permet l'accès par plusieurs threads en même temps. Différents threads peuvent généralement parcourir le contenu de la collection et ajouter ou supprimer des éléments. La collection est chargée de veiller à ce que la collection ne soit pas corrompue. [1]: http://stackoverflow.com/documentation/java/90/collections#t=201612221936497298484

Collections à filetage sécurisé

Par défaut, les différents types de collections ne sont pas compatibles avec les threads.

Cependant, il est assez facile de rendre une collection thread-safe.

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>());

Lorsque vous créez une collection thread-safe, vous ne devez jamais y accéder via la collection d'origine, uniquement via l'encapsuleur thread-safe.

Java SE 5

À partir de Java 5, java.util.collections possède plusieurs nouvelles collections sécurisées pour les threads qui n'ont pas besoin des diverses méthodes Collections.synchronized .

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

Collections concurrentes

Les collections simultanées sont une généralisation des collections thread-safe, ce qui permet une utilisation plus large dans un environnement concurrent.

Bien que les collections thread-safe disposent d'un ajout ou d'une suppression d'éléments sûrs dans plusieurs threads, elles n'ont pas nécessairement une itération sécurisée dans le même contexte (il est possible de ne pas itérer en toute sécurité dans un thread, tandis qu'un autre le modifie en ajoutant / enlever des éléments).

C'est là que les collections concurrentes sont utilisées.

Comme l'itération est souvent l'implémentation de base de plusieurs méthodes en vrac dans des collections, comme addAll , removeAll ou également la copie de collection (via un constructeur ou un autre moyen), le tri ...

Par exemple, le fichier Java SE 5 java.util.concurrent.CopyOnWriteArrayList est une implémentation Lis t sécurisée et simultanée de threads, dont le javadoc stipule:

La méthode d'itérateur de style "instantané" utilise une référence à l'état du tableau au moment où l'itérateur a été créé. Ce tableau ne change jamais pendant la durée de vie de l'itérateur, de sorte que l'interférence est impossible et que l'itérateur est assuré de ne pas lancer l'exception ConcurrentModificationException.

Par conséquent, le code suivant est sécurisé:

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 , qui indique:

Les itérateurs sont faiblement cohérents, renvoyant des éléments reflétant l'état de la file d'attente à un moment donné ou depuis la création de l'itérateur. Ils ne lancent pas java.util.ConcurrentModificationException et peuvent continuer simultanément avec d'autres opérations. Les éléments contenus dans la file d'attente depuis la création de l'itérateur seront renvoyés exactement une fois.

On devrait vérifier les javadocs pour voir si une collection est concurrente ou non. Les attributs de l'itérateur renvoyés par la méthode iterator() ("échec rapide", "peu cohérent", ...) constituent l'attribut le plus important à rechercher.

Thread safe mais exemples non concurrents

Dans le code ci-dessus, changer la déclaration LIST en

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

Pourrait (et statistiquement sera sur la plupart des architectures multi-CPU / core modernes) conduire à des exceptions.

Les collections synchronisées à partir des méthodes de l'utilitaire Collections sont sécurisées pour l'ajout / suppression d'éléments, mais pas pour l'itération (à moins que la collection sous-jacente ne lui soit déjà transmise).

Insertion dans 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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow