Implémentations de la file d'attente Java, laquelle?

De Javadoc:

  • Un ConcurrentLinkedQueue est un bon choix lorsque plusieurs threads de partager l'accès à un ensemble commun. Cette file d'attente ne permet pas les éléments nuls.
  • ArrayBlockingQueue est un "tampon borné" classique, dans lequel un tableau de taille fixe contient des éléments insérés par les producteurs et extraits par les consommateurs. Cette classe soutient une politique d'équité facultative pour commande de fils de producteur et de consommateur en attente
  • LinkedBlockingQueue ont généralement un débit plus élevé que les files d'attente basées sur des réseaux, mais des performances moins prévisibles dans la plupart des applications concurrentes.

j'ai 2 scénarios, l'un nécessite la file d'attente pour soutenir de nombreux producteurs (fils l'utilisant) avec un consommateur et l'autre est l'inverse.

Je ne comprends pas si je devrais utiliser ConcurrentLikedQueue ou les autres (le tableau ou linkedList implémentations). Pourquoi toutes ces implémentations sont censées être simultanées? Je veux dire, quelqu'un peut m'expliquer quelle est la différence entre ConcurrentLikedQueue et LinkedBlockingQueue ?

aussi, Quelle est la Politique d'équité facultative dans le ArrayBlockingQueue s'il vous plaît?

106
demandé sur David Hofmann 2009-08-19 22:12:13

6 réponses

fondamentalement, la différence entre eux sont les caractéristiques de performance et le comportement de blocage.

en prenant la première plus facile, ArrayBlockingQueue est une file d'attente d'une taille fixe. Donc, si vous réglez la taille à 10, et essayez d'insérer une 11ème élément, l'instruction insert bloqué jusqu'à ce qu'un autre thread supprime un élément. La question de l'équité est ce qui se passe si plusieurs threads tentent d'insérer et de supprimer en même temps (en d'autres termes, pendant la période où la file d'attente a été bloquer.) Un algorithme d'équité garantit que le premier thread qui demande est le premier thread qui obtient. Dans le cas contraire, un thread donné peut attendre plus longtemps que les autres threads, provoquant un comportement imprévisible (parfois un thread ne prendra que quelques secondes parce que les autres threads qui ont commencé plus tard ont été traités en premier). Le compromis est que cela prend des frais généraux pour gérer l'équité, ce qui ralentit le débit.

la différence La plus importante entre LinkedBlockingQueue et ConcurrentLinkedQueue est que si vous demandez un élément d'un LinkedBlockingQueue et que la file d'attente est vide, votre thread attendra jusqu'à ce qu'il y ait quelque chose. Un ConcurrentLinkedQueue reviendra immédiatement avec le comportement d'une file d'attente vide.

sur lequel on dépend si vous avez besoin du blocage. Là où il y a beaucoup de producteurs et un consommateur, on dirait bien. D'autre part, lorsque vous avez de nombreux consommateurs et un seul producteur, vous ne pouvez pas besoin du comportement de blocage, et peut-être heureux de juste avoir les consommateurs de vérifier si la file d'attente est vide, et se déplacer sur si il est.

38
répondu Yishai 2018-09-10 16:17:15

ConcurrentLinkedQueue signifie qu'aucune écluse n'est prise (c.-à-d. aucune écluse synchronisée(la présente) ou ).verrouiller appels). Il utilisera une opération CAS - Compare et Swap pendant les modifications pour voir si le noeud tête/queue est toujours le même que quand il a commencé. Si oui, l'opération réussit. Si le noeud tête / queue est différent, il tournera autour et essaiera à nouveau.

LinkedBlockingQueue sera verrouillé avant toute modification. Donc vos appels d'offre bloqueraient jusqu'à ce qu'ils obtiennent la serrure. Vous pouvez utiliser la surcharge de l'offre qui prend un temps D'unité pour dire que vous êtes seulement prêt à attendre X quantité de temps avant d'abandonner l'add (généralement bon pour les files d'attente de type de message où le message est périmé après X nombre de millisecondes).

équité signifie que l'implémentation de la serrure maintiendra les threads ordonnés. Signification si le fil A entre et puis le fil B entre, le fil A aura la serrure en premier. Sans équité, il est indéfini vraiment ce qui se passe. Il sera très probablement le prochain fil qui est prévu.

comme pour lequel on utilise, cela dépend. J'ai tendance à utiliser ConcurrentLinkedQueue parce que le temps qu'il faut à mes producteurs pour obtenir du travail à mettre sur la file d'attente est diverse. Je n'ai pas beaucoup de producteurs produisant exactement au même moment. Mais le consommateur est plus compliqué parce que sondage ne pas aller dans un bon état de veille. Vous avez à gérer vous-même.

97
répondu Justin Rudd 2009-08-19 19:20:53

le titre de votre question mentionne le blocage des files d'attente. Toutefois, ConcurrentLinkedQueue est et non une file d'attente de blocage.

les BlockingQueue s sont ArrayBlockingQueue , DelayQueue , LinkedBlockingDeque , LinkedBlockingQueue , PriorityBlockingQueue , et SynchronousQueue .

certains d'entre eux ne sont manifestement pas adaptés à votre usage ( DelayQueue , PriorityBlockingQueue , et SynchronousQueue ). LinkedBlockingQueue et LinkedBlockingDeque sont identiques, sauf ce dernier est une file d'attente à double extrémité (il implémente l'interface Deque).

puisque ArrayBlockingQueue n'est utile que si vous voulez limiter le nombre d'éléments, Je m'en tiens à LinkedBlockingQueue .

7
répondu Powerlord 2014-04-21 20:02:25

ArrayBlockingQueue a une empreinte mémoire plus faible, il peut réutiliser l'élément node, pas comme LinkedBlockingQueue qui doivent créer un objet LinkedBlockingQueue$Node pour chaque nouvelle insertion.

3
répondu Deng 2013-01-31 12:30:15
  1. SynchronousQueue ( tiré d'un autre question )

SynchronousQueue est plus un transfert, alors que le LinkedBlockingQueue ne permet qu'un seul élément. La différence étant que l'appel put() à un appel SynchronousQueue ne reviendra pas tant qu'il n'y aura pas un appel take() correspondant, mais avec un appel LinkedBlockingQueue de taille 1, l'appel put() (à une file d'attente vide) reviendra immédiatement. C'est essentiellement l' BlockingQueue implémentation pour quand vous ne voulez pas vraiment une file d'attente (vous ne voulez pas maintenir de données en attente).

  1. LinkedBlockingQueue ( LinkedList implémentation mais pas exactement JDK implémentation de LinkedList il utilise le noeud de classe interne statique pour maintenir les liens entre les éléments)

Constructeur de LinkedBlockingQueue

public LinkedBlockingQueue(int capacity) 
{
        if (capacity < = 0) throw new IllegalArgumentException();
        this.capacity = capacity;
        last = head = new Node< E >(null);   // Maintains a underlying linkedlist. ( Use when size is not known )
}

classe de Nœud Utilisé pour Maintenir les Liens

static class Node<E> {
    E item;
    Node<E> next;
    Node(E x) { item = x; }
}

3 . ArrayBlockingQueue ( Matrice De Mise En Œuvre )

Constructeur de ArrayBlockingQueue

public ArrayBlockingQueue(int capacity, boolean fair) 
{
            if (capacity < = 0)
                throw new IllegalArgumentException();
            this.items = new Object[capacity]; // Maintains a underlying array
            lock = new ReentrantLock(fair);
            notEmpty = lock.newCondition();
            notFull =  lock.newCondition();
}

IMHO plus grande différence entre ArrayBlockingQueue et LinkedBlockingQueue est clair de constructeur un a tableau de structure de données sous-jacente et autre liste liée .

ArrayBlockingQueue utilise single-lock double condition de l'algorithme de et LinkedBlockingQueue est une variante de l'algorithme" two lock queue " et il a 2 serrures 2 conditions (takeLock , putLock)

1
répondu Vipin 2018-09-10 16:20:11

ConcurrentLinkedQueue est sans verrouillage, LinkedBlockingQueue ne l'est pas. Chaque fois que vous invoquez LinkedBlockingQueue.put () ou LinkedBlockingQueue.take (), vous devez d'abord acquérir la serrure. En d'autres termes, LinkedBlockingQueue a une mauvaise concurrence. Si vous vous souciez de la performance, essayez le support queue + Lock.

0
répondu user319609 2015-05-14 11:57:10