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?
Réponses
Trop de publicités?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
etDeque
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 commeget
etcontains
, 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 deArrayList
?Non ... il y a d'autres alternatives:
Collections.synchronizedList(...);
CopyOnWriteList
,- simultanées
Queue
ouDeque
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)
Si vous voulez avoir un Synchronisé ArrayList vous pouvez utiliser cette.
List list = Collections.synchronizedList(new ArrayList());
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
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.
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 pourVector
.Vector
etArrayList
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.