61 votes

Quand dois-je utiliser SynchronousQueue plutôt que LinkedBlockingQueue ?

new SynchronousQueue()
new LinkedBlockingQueue(1)

Quelle est la différence ? Quand dois-je utiliser SynchronousQueue contre LinkedBlockingQueue avec la capacité 1 ?

62voto

jtahlborn Points 32515

La SynchronousQueue est plus un transfert, alors que la LinkedBlockingQueue ne permet qu'un seul élément. La différence est que l'appel put() à une SynchronousQueue ne reviendra pas jusqu'à ce qu'il y ait un appel take() correspondant, mais avec une LinkedBlockingQueue de taille 1, l'appel put() (vers une file d'attente vide) reviendra immédiatement.

Je ne peux pas dire que j'ai déjà utilisé la SynchronousQueue directement moi-même, mais c'est la BlockingQueueue par défaut utilisée pour l'application Executors.newCachedThreadPool() méthodes. Il s'agit essentiellement de l'implémentation de BlockingQueue pour les cas où l'on ne veut pas vraiment voulez une file d'attente (vous ne voulez pas maintenir de données en attente).

10voto

bestsss Points 6403

D'après ce que je comprends, les codes ci-dessus font les mêmes choses.

Non, le code n'est pas du tout le même.

Sync.Q. exige la présence d'un ou de plusieurs serveurs pour que l'offre soit acceptée. LBQ gardera l'article et l'offre se terminera immédiatement même s'il n'y a pas de serveur.

SyncQ est utile pour le transfert des tâches. Imaginez que vous avez une liste avec des tâches en attente et 3 threads disponibles qui attendent dans la file d'attente, essayez de faire ce qui suit offer() avec 1/4 de la liste si elle n'est pas acceptée, le fil peut exécuter la tâche tout seul. [le dernier 1/4 doit être géré par le thread actuel, si vous vous demandez pourquoi 1/4 et pas 1/3].

Pensez à essayer de confier la tâche à un travailleur, si aucun n'est disponible, vous avez la possibilité d'exécuter la tâche par vous-même (ou de lever une exception). Au contraire, avec LBQ, laisser la tâche dans la file d'attente ne garantit pas son exécution.

Note : le cas des consommateurs et des éditeurs est le même, c'est-à-dire que l'éditeur peut bloquer et attendre les consommateurs mais après offer o poll retourne, il assure que la tâche/élément doit être traité.

7voto

snadata Points 11

L'une des raisons d'utiliser SynchronousQueue est d'améliorer les performances des applications. Si vous devez effectuer un transfert entre les threads, vous aurez besoin d'un objet de synchronisation. Si vous pouvez satisfaire les conditions requises pour son utilisation, SynchronousQueue est l'objet de synchronisation le plus rapide que j'ai trouvé. D'autres sont d'accord. Voir : Mise en œuvre de BlockingQueue : Quelles sont les différences entre SynchronousQueue et LinkedBlockingQueue ?

2voto

anir Points 885

(J'essaie juste de l'exprimer avec des mots (peut-être) plus clairs.)

Je crois que le SynchronousQueue Documents de l'API énonce les choses très clairement :

  1. Une file d'attente bloquante dans laquelle chaque opération d'insertion doit attendre une opération de suppression correspondante par un autre thread, et vice versa.
  2. Une file d'attente synchrone n'a pas de capacité interne, pas même une capacité de un. Vous ne pouvez pas consulter une file d'attente synchrone car un élément n'est présent que lorsque vous essayez de le retirer ; vous ne pouvez pas insérer un élément (en utilisant n'importe quelle méthode) à moins qu'un autre thread n'essaie de le retirer ; vous ne pouvez pas itérer car il n'y a rien à itérer.
  3. La tête de la file d'attente est l'élément que le premier thread d'insertion en file d'attente tente d'ajouter à la file d'attente ; s'il n'y a pas de thread en file d'attente, aucun élément n'est disponible pour être retiré et poll() retournera null .

Et BlockingQueue Documents de l'API :

  1. Une file d'attente qui prend en charge les opérations qui attendent que la file d'attente ne soit pas vide lors de la récupération d'un élément, et qui attendent qu'un espace se libère dans la file d'attente lors du stockage d'un élément.

La différence est donc évidente et quelque peu subtile sur le plan critique, notamment le 3e point ci-dessous :

  1. Si la file d'attente est vide lorsque vous récupérez des données dans la base de données de la BlockingQueue le bloc d'opérations jusqu'à ce que le nouvel élément soit inséré. De même, si la file d'attente est pleine au moment de l'insertion dans le fichier BlockingQueue l'opération sera bloquée jusqu'à ce que l'élément soit retiré de la file d'attente et qu'un espace soit créé pour la nouvelle file d'attente. Cependant, notez que dans SynchronousQueue En effet, l'opération est bloquée pour que l'opération opposée (l'insertion et la suppression sont opposées l'une à l'autre) se produise sur un autre thread. Donc, contrairement à BlockingQueue le blocage dépend de l'existence de l'opération, et non de l'existence ou de la non existence d'un élément. .
  2. Comme le blocage dépend de l'existence de l'opération inverse, l'élément n'est jamais vraiment inséré dans la file d'attente. C'est pourquoi le deuxième point : " Une file d'attente synchrone n'a pas de capacité interne, pas même une capacité de un. "
  3. En conséquence, peek() retourne toujours null (à nouveau, vérifiez le [Document API](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/SynchronousQueue.html#peek()) ) et iterator() renvoie un itérateur vide dans lequel hasNext() retourne toujours false . ( [Document API](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/SynchronousQueue.html#iterator()) ). Toutefois, il convient de noter que le poll() récupère et supprime proprement la tête de cette file d'attente, si un autre thread est en train de mettre un élément à disposition et si aucun thread de ce type n'existe, elle renvoie la méthode null . ( [Document API](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/SynchronousQueue.html#poll()) )

Enfin, une petite note, les deux SynchronousQueue y LinkedBlockingQueue les classes mettent en œuvre BlockingQueue interface.

1voto

Deepa Bhatia Points 21

SynchronousQueue fonctionne de manière similaire avec les différences majeures suivantes : 1) La taille de SynchronousQueue est de 0. 2) La méthode put() n'insère un élément que si la méthode take() est capable de récupérer cet élément de la file d'attente au même moment, c'est-à-dire qu'un élément ne peut pas être inséré si l'appel take() du consommateur va prendre un certain temps pour le consommer.

SynchronousQueue - Insertion uniquement lorsque quelqu'un la recevra à ce moment même.

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