45 votes

Comment interrompre la ligne de lecture de BufferedReader

J'essaie de lire l'entrée d'une socket ligne par ligne dans plusieurs threads. Comment puis-je interrompre readLine() afin de pouvoir gracieusement arrêter le thread qu'il bloque?

EDIT (bounty) : Cela peut-il être fait sans fermer le socket?

30voto

Sans fermer la socket:

Le difficile problème n'est pas l' BufferedReader.readLine, mais le sous-jacent read. Si un thread est bloqué, la lecture, la seule façon de l'obtenir est de fournir des données réelles ou fermer le socket (interrompant le fil probablement devrait fonctionner, mais dans la pratique, ne prend pas).

Donc, la solution évidente est d'avoir deux fils. Celui qui lit les données brutes, et restera bloquée. La seconde, sera le thread appelant readLine. Tuyau de données à partir de la première à la seconde. Vous avez alors accès à un verrou qui peut être utilisé pour de réactivation de la deuxième thread, et de prendre les mesures appropriées.

Il y a des variations. Vous pourriez avoir le premier thread à l'aide de NIO, avec un seul thread instance partagée entre tous les consommateurs.

Sinon, vous pourriez écrire un readLine qui fonctionne avec NIO. Cela pourrait même prendre un relativement simple single-threaded forme, comme en Selector.wakeup existe et fonctionne.

24voto

Steve Emmerson Points 4161

Fermez la prise sur le fil d'interruption. Cela provoquera une exception sur le thread interrompu.

Pour plus d'informations sur ce problème et d'autres problèmes de concurrence, je recommande fortement le livre de Brian Goetz "Java Concurrency in Practice".

9voto

bnsmith Points 926

Je jouais avec cela récemment (en utilisant Scala), et je n'aimais pas la réponse acceptée de fermer le socket et d'obtenir une exception.

Finalement, j'ai découvert qu'il était possible d'appeler socket.shutdownInput() dans le thread d'interruption pour sortir de l'appel readLine sans exception. Je fais cet appel dans un gestionnaire SIGINT afin de pouvoir nettoyer et fermer le socket dans le thread principal.

Notez que l'équivalent existe pour le flux de sortie avec socket.shutdownOutput()

0voto

mhshams Points 3839

vous pouvez concevoir une classe Timer autour du bloc read ().

vous devez définir une temporisation pour votre minuterie.

à l'expiration interrompez simplement votre fil.

-1voto

Michael Points 9231

Je pense que vous devrez peut-être utiliser autre chose que readLine() . Vous pouvez utiliser read() et à chaque itération de boucle vérifier pour voir si le thread a été interrompu et sortir de la boucle si c'était le cas.

 BufferedReader reader = //...
int c;
while ((c = reader.read()) != -1){
  if (Thread.isInterrupted()){
    break;
  }
  if (c == '\n'){
    //newline
  }
  //...
}
 

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