2011-07-12 4 views
3

La Javadoc pour AsynchronousByteChannel.read() indique que l'opération a lieu de manière asynchrone, mais que se passe-t-il lorsque la fin du flux a été atteinte? Une implémentation est-elle autorisée à déclencher le gestionnaire de complétion dans le même thread qui a appelé read()? Du point de vue de la mise en œuvre, il n'y a aucune raison d'effectuer cette opération de manière asynchrone, car nous connaissons déjà le résultat. De même, si un utilisateur tente de lire dans un ByteBuffer où remaining() renvoie 0, nous savons que l'opération de lecture doit renvoyer 0.Implications Threading de AsynchronousByteChannel

Je demande parce que j'ai rencontré une condition de concurrence dans ma propre implémentation AsynchronousByteChannel. J'appelle un gestionnaire d'achèvement qui appelle notify() sur lui-même lorsque l'opération se termine. J'invoque alors le code utilisateur suivant:

CompletionHandler<?, ?> handler = ...; 
synchronized (handler) 
{ 
    asyncByteChannel.read(handler); 
    handler.wait(); 
} 

Notez que l'utilisateur est en supposant que le gestionnaire sera informé lorsque l'opération est terminée, mais parce que lire() Invoque fait l'achèvement-gestionnaire synchrone, il est notifié avant attente() et ce dernier bloquera pour toujours.

La spécification nécessite-t-elle que Update CompletionHandler soit mis à jour dans un thread distinct ou les utilisateurs doivent-ils être conscients du fait que le thread qui appelle read() peut effectuer certaines opérations de manière synchrone?

+1

Son modèle d'enfilage est un gâchis. Le javadoc sur le groupe asynchrone est impossible à analyser. Threading devrait être laissé aux développeurs - c'est la partie facile.Malheureusement, ils ont décidé de nous aider à ce sujet. Le résultat est très compliqué, non intuitif, mal documenté (parce qu'ils ne peuvent pas expliquer le désordre). Un examinateur occasionnel pourrait trouver l'API bien - en effet, pourquoi devrait-il être difficile? Mais quand on construit sérieusement une application sur le dessus, les complexités vont le rendre fou. – irreputable

Répondre

1

En regardant http://www.docjar.com/html/api/sun/nio/ch/AsynchronousSocketChannelImpl.java.html, ils mettent toujours à jour CompletionHandler dans un thread séparé, mais Future est mis à jour dans le même thread. Rechercher la variable hasSpaceToRead pour trouver la méthode en question.

Je devine que leur raisonnement va quelque chose comme ceci:

  1. Nous créons l'avenir est revenu à l'utilisateur donc il n'y a aucun moyen, il est en interaction avec elle (synchronisation, etc.) avant de retourner la objet.
  2. L'utilisateur crée le CompletionHandler, donc nous n'avons aucun moyen de contrôler ce que l'implémentation fait (pour autant que nous sachions, nous pourrions déclencher un blocage!). Ne prenez pas de risque, lancez le gestionnaire de complétion dans un fil séparé.

MISE À JOUR: J'ai corrigé. Selon Invoker.invoke() "Si le thread en cours est dans le pool de threads du groupe de canaux, le gestionnaire est appelé directement, sinon il est appelé indirectement."

résolu: Selon http://download.oracle.com/javase/7/docs/api/java/nio/channels/AsynchronousChannelGroup.html « Lorsqu'une opération d'E/S se termine immédiatement, et le fil d'amorçage est l'un des fils mis en commun dans le groupe, alors le gestionnaire d'achèvement peut être appelé directement par le fil d'amorçage. »

1

Même lorsque le gestionnaire est appelé sur un autre thread, il n'y a aucune garantie qu'il sera invoqué après la méthode renvoie read, à savoir après votre wait() a commencé. (D'accord, le verrou de synchronisation semble garantir.)

Vous devez utiliser la synchronisation et une variable booléenne pour l'attente et le verrouillage:

CompletionHandler<?, ?> handler = ...; 
synchronized (handler) 
{ 
    asyncByteChannel.read(handler); 
    while(!handler.finished) { 
    handler.wait(); 
    } 
} 

... et votre gestionnaire sera alors la variable finished à vrai.

+0

Votre solution proposée est géniale ** si ** Je suis autorisé à traiter le CompletionHandler sur le thread principal. On ne sait toujours pas si c'est le cas :) – Gili

+0

Non, la solution est toujours utilisable. (Ce n'est pas nécessaire si ce n'est pas autorisé - mais vous devriez attendre dans une boucle de toute façon, car il peut y avoir des réveils intempestifs.) –

+0

Je suis d'accord, mais ce n'est pas ce que cette question concerne. Il s'agit de savoir si la spécification permet de notifier sur le même thread. – Gili