43 votes

Pourquoi n'est-il pas Simultanées liste de tableaux en java.util.simultanées paquet

JDK 5 introduit ConcurrentHashMap dans le java.util.simultanées paquet. On peut l'utiliser à la place de la table de hachage dans le package. Pourquoi n'est-il pas Simultanées liste de tableaux en java.util.simultanées paquet. Pouvons nous utiliser que les Vecteur pour mutil-contexte de thread au lieu de ArrayList? Pourquoi n'avons-nous pas une classe pour remplacer le Vecteur dans la concurrente de package?

62voto

Stephen C Points 255558

Pourquoi n'est-il pas Simultanées liste de tableaux en java.util.simultanées paquet.

Je pense que la raison principale est qu'il est difficile de comprendre comment vous pourriez code général thread-safe tableau liste(*) qui ne sont pas inhérentes à la simultanéité des goulets d'étranglement.

Le point réel / valeur de classes comme l' ConcurrentHashMap n'est pas qu'ils sont thread-safe. C'est qu'ils sont thread-safe, sans être un goulot d'étranglement de la simultanéité. Par exemple, ConcurrentHashMap évite les goulots d'étranglement en ayant serrures différentes pour les différentes parties de la table, et de l'assouplissement de la sémantique de la carte des itérateurs.

Le problème avec le "tableau liste" famille de structures de données, c'est qu'il n'est pas évidente de la façon dont vous pouvez éviter les goulets d'étranglement. Prendre l' contains() opération par exemple. Comment pouvez-vous éviter le blocage de l'ensemble de la liste alors que vous recherche de l'élément?

L'autre observation est que l' Queue et Deque les interfaces n'ont simultanées implémentations (basé sur les listes chaînées). Ces Api sont plus limités que l' List API, mais il est des limitations qui rend simultanées implémentations possibles; c.f. l' List.contains(...) problème.


(* CopyOnWriteArrayList Classe est un cas intéressant. Il évite la simultanéité de goulot d'étranglement sur les opérations en lecture seule comme get et contains, mais il le fait en faisant beaucoup plus de travail dans la mutation des opérations, et en modifiant les règles de visibilité. En outre, la mutation des opérations de verrouillage de l'ensemble de la liste, et sont donc un goulot d'étranglement de la simultanéité. Ces propriétés dire qu' CopyOnWriteArrayList ne peut pas être appelé un usage général liste concurrente.)


Pouvons-nous seulement utiliser Vector pour le multi-thread contexte au lieu de ArrayList?

Non ... il y a d'autres alternatives:

  • Collections.synchronizedList(...);
  • CopyOnWriteList,
  • simultanées Queue ou Deque des implémentations (si vous avez seulement besoin d'un sous-ensemble de la fonctionnalité de la liste)
  • adapté de la 3e partie de la liste des implémentations (si vous pouvez les trouver), ou
  • liste personnalisée des implémentations (si vos besoins sont spécialisées)

22voto

TikkaBhuna Points 415

Si vous voulez avoir un Synchronisé ArrayList vous pouvez utiliser cette.

List list = Collections.synchronizedList(new ArrayList()); 

9voto

Récemment, j'ai été aussi à la recherche d'un efficace et thread-safe Liste. Je n'étais pas satisfait avec les implémentations comme, Vecteur et des Collections.synchronizedList(). Principalement en raison du fait que les deux de ces mises en rend la lecture (get) et en écriture (set) les opérations de la Liste de l'objet de critiques pour obtenir le niveau de l'objet de verrouillage. Alors j'ai regardé pour les implémentations de la donnée en java.simultanées paquet et j'ai trouvé CopyOnWriteArrayList.

CopyOnWriteArrayList a un rendement inconvénient, car il crée une copie de la sous-matrice de la liste sur les opérations d'écriture. Le tableau de la copie est de rendre les opérations d'écriture lente. Peut-être, CopyOnWriteArrayList est avantageux pour une utilisation d'une Liste avec un haut taux de lecture et d'écriture faible taux.

Finalement, j'ai commencé à coder ma propre mise en œuvre à l'aide de java.util.de façon concomitante.serrures,ReadWriteLock. J'ai fait ma mise en œuvre simplement en maintenant au niveau de l'objet ReadWriteLock exemple, et d'acquérir le verrou en lecture dans les opérations de lecture et d'acquérir le verrou d'écriture dans les opérations d'écriture. Le code ressemble à ceci.

public class ConcurrentList< T > implements List< T >
{
    private final ReadWriteLock  readWriteLock = new ReentrantReadWriteLock();
    private final List< T > list;

    public ConcurrentList( List<T> list )
    {
        this.list = list;
    }

    public boolean remove( Object o )
    {
        readWriteLock.writeLock().lock();
        boolean ret;
        try
        {
            ret = list.remove( o );
        }
        finally
        {
            readWriteLock.writeLock().unlock();
        }
        return ret;
    }

    public boolean add( T t )
    {
        readWriteLock.writeLock().lock();
        boolean ret;
        try
        {
            ret = list.add( t );
        }
        finally
        {
            readWriteLock.writeLock().unlock();
        }
        return ret;
    }

    public void clear()
    {
        readWriteLock.writeLock().lock();
        try
        {
            list.clear();
        }
        finally
        {
            readWriteLock.writeLock().unlock();
        }
    }


    public int size()
    {
        readWriteLock.readLock().lock();
        try
        {
            return list.size();
        }
        finally
        {
            readWriteLock.readLock().unlock();
        }
    }

    public boolean contains( Object o )
    {
        readWriteLock.readLock().lock();
        try
        {
            return list.contains( o );
        }
        finally
        {
            readWriteLock.readLock().unlock();
        }
    }

    public T get( int index )
    {
        readWriteLock.readLock().lock();
        try
        {
            return list.get( index );
        }
        finally
        {
            readWriteLock.readLock().unlock();
        }
    }

//etc
}

L'amélioration de la performance observée a été notable.

Temps Total nécessaire pour 5000 lit + de 5000 write ( lecture / écriture ratio est de 1:1) par 10 threads ont été

  • Liste de tableaux - 16450 ns( non thread-safe)
  • ConcurrentList - 20999 ns
  • Vecteur -35696 ns
  • CopyOnWriteArrayList - 197032 ns

veuillez suivre ce lien pour plus d'informations sur les cas de test utilisé pour l'obtention de résultats ci-dessus

Toutefois, afin d'éviter ConcurrentModificationException lors de l'utilisation de l'Itérateur, je viens de créer une copie de la Liste actuelle, et a renvoyé l'itérateur. Cela veut dire que cette liste n'est pas de retour et d'Itérateur qui peut modifier la Liste d'origine. Eh bien, pour moi, c'est de l'o.k. pour le moment.

public Iterator<T> iterator()
    {
        readWriteLock.readLock().lock();
        try
        {
            return new ArrayList<T>( list ).iterator();
        }
        finally
        {
            readWriteLock.readLock().unlock();
        }
    }

Après quelques recherches sur google, j'ai trouvé que CopyOnWriteArrayList a un semblable implementaion, comme elle ne retourne un Itérateur qui peut modifier la Liste d'origine. Javadoc dit,

Le retour de l'itérateur fournit un instantané de l'état de la liste lorsque l'itérateur a été construit. Aucune synchronisation n'est nécessaire lors de la traversée de l'itérateur. L'itérateur ne prend PAS en charge la méthode remove.

2voto

Cratylus Points 21838

Pourquoi n'avons-nous pas une classe pour remplacer le Vecteur dans le simultanées package?

L' ArrayList classe est la Collection du Cadre de remplacement pour Vector.
Vector et ArrayList sont fonctionnellement équivalent à la différence que l' ArrayList est pas synchronisé.
Cela signifie qu'il n'y a pas de pénalité sur les performances lorsque vous avez besoin d'utiliser une liste sans simultanéité et si vous avez besoin d'un accès par de multiples theads vous pouvez toujours obtenir une version thread-safe à l'aide d'un Synchronisé Liste
Si vous n'avez pas de th la surcharge de la synchronisation si vous en avez besoin.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X