web-dev-qa-db-fra.com

Quand devrais-je utiliser SynchronousQueue

new SynchronousQueue()
new LinkedBlockingQueue(1)

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

49
Anton

la SynchronousQueue est plus un transfert, alors que la LinkedBlockingQueue ne permet qu'un seul élément. La différence étant que l'appel put () à une SynchronousQueue ne retournera pas jusqu'à ce qu'il y ait un appel take () correspondant, mais avec une LinkedBlockingQueue de taille 1, l'appel put () (vers une file 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 BlockingQueue par défaut utilisée pour les méthodes Executors.newCachedThreadPool(). Il s’agit essentiellement de l’implémentation de BlockingQueue pour les cas où vous ne voulez pas {vraiment} _ une file d’attente (vous ne souhaitez pas conserver les données en attente).

45
jtahlborn

Autant que je sache, le code ci-dessus fait la même chose.

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

Sync.Q. nécessite d'avoir un ou plusieurs serveurs pour que l'offre réussisse. LBQ conservera 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 de tâches. Imaginez que vous avez une liste de tâches en attente et 3 threads disponibles en attente dans la file d'attente, essayez offer() avec 1/4 de la liste si elle n'est pas acceptée, le thread peut exécuter la tâche seul. [le dernier quart devrait être traité par le fil actuel, si vous vous demandez pourquoi 1/4 et non 1/3]

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

Remarque: le cas avec les consommateurs et les éditeurs est identique, c’est-à-dire que l’éditeur peut bloquer et attendre les consommateurs, mais après le retour de offer ou poll, il garantit que la tâche/l’élément doit être traité.

9
bestsss

Une des raisons d'utiliser SynchronousQueue est d'améliorer les performances des applications. Si vous devez avoir un transfert entre les threads, vous aurez besoin d'un objet de synchronisation. Si vous pouvez satisfaire aux conditions requises pour son utilisation, SynchronousQueue est l'objet de synchronisation le plus rapide que j'ai trouvé. Les autres sont d'accord. Voir: Implémentation de BlockingQueue: Quelles sont les différences entre SynchronousQueue et LinkedBlockingQueue

6
snadata

[J'essaie juste de le formuler (éventuellement) en termes plus clairs.]

Je crois que la SynchronousQueue API docs é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 inversement. 
  2. Une file d'attente synchrone n'a aucune capacité interne, pas même une capacité de un. Vous ne pouvez pas jeter un coup d'œil sur une file d'attente synchrone car un élément n'est présent que lorsque vous essayez de le supprimer. vous ne pouvez pas insérer un élément (quelle que soit la méthode) à moins qu'un autre thread ne tente de le supprimer; 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 tel thread en file d'attente, aucun élément n'est disponible pour la suppression et poll() renverra null.

Et BlockingQueue Docs de l'API :

  1. Une file d'attente qui prend également en charge les opérations qui attendent que la file devienne non vide lors de la récupération d'un élément et qui attend que de l'espace soit disponible dans la file lors du stockage d'un élément.

La différence est donc évidente et légèrement subtile, en particulier le troisième point ci-dessous:

  1. Si la file d'attente est vide lors de la récupération de BlockingQueue, le bloc d'opération est inséré jusqu'à ce que le nouvel élément soit inséré. De plus, si la file d'attente est pleine lorsque vous insérez la variable 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, l'opération étant bloquée pour une opération opposée (les opérations d'insertion et de suppression sont opposées) sur un autre thread. Ainsi, contrairement à BlockingQueue, le blocage dépend de l'existence de l'opération, au lieu de l'existence ou de la non-existence d'un élément.
  2. Comme le blocage dépend de l'existence d'opérations opposées, l'élément n'est jamais réellement inséré dans la file d'attente. C'est pourquoi le deuxième point: "Une file d'attente synchrone n'a aucune capacité interne, pas même une capacité de un."
  3. Par conséquent, peek() renvoie toujours null (à nouveau, vérifiez le API doc ) et iterator() renvoie un itérateur vide dans lequel hasNext() renvoie toujours false. ( API doc ). Cependant, notez que la méthode poll() récupère et supprime parfaitement la tête de cette file d'attente, si un autre thread met actuellement un élément à disposition et si aucun tel thread n'existe, il retourne null. ( doc API )

Enfin, une petite remarque, les classes SynchronousQueue et LinkedBlockingQueue implémente l'interface BlockingQueue.

0
anir

SynchronousQueue fonctionne de la même manière, avec les différences majeures suivantes: queue au même moment, c’est-à-dire qu’un élément ne peut pas être inséré si l’appel consommateur take () met un certain temps à le consommer.

SynchronousQueue - N'insérez que lorsque quelqu'un le recevra à ce moment même.

0
Deepa Bhatia