J'ai une opération de blocage en cours d'exécution dans un thread que je dois arrêter:

Future serverFuture = Executors.newCachedThreadPool().submit(() -> {
    var serverSocket = new ServerSocket(Config.SERVER_PORT);

    serverSocket.accept(); // <-- blocking
});

serverFuture.cancel(true);

Normalement, j'implémenterais une boucle qui continuerait à vérifier si le thread est interrompu et à l'arrêter éventuellement. Cependant, puisque le thread est bloqué dans la méthode serverSocket.accept(), cela n'est pas possible.

Quelle est la manière habituelle de surmonter ce problème?

1
Martin Heralecký 27 janv. 2019 à 21:44

3 réponses

Meilleure réponse

Comment arrêter correctement un thread qui exécute une opération de blocage?

En général, vous ne pouvez pas. Mais il y a des choses que vous pouvez faire pour certaines opérations spécifiques . Par exemple, vous pouvez essayer d'interrompre le thread. Dans un cas tel que votre exemple, où vous n'avez pas d'accès direct au Thread dans lequel la tâche s'exécute, vous pouvez utiliser Future.cancel():

serverFuture.cancel(true);

Mais les opérations de blocage ne sont pas nécessairement interrompues lorsque leurs threads le font. Ceux qui le font sont généralement documentés pour lancer InterruptedException, et cela ne fait pas partie des exceptions ServerSocket.accept() est déclaré lancer. Pour cette méthode en particulier, votre meilleur pari consiste probablement à utiliser ServerSocket.setSoTimeout() pour mettre une limite supérieure appropriée sur le temps que accept() bloquera. L'utilisation d'un délai d'attente relativement court et l'exécution du accept() en boucle vous permettrait de vérifier périodiquement s'il faut abandonner la tâche.

Dans l'ensemble, vous devez donc choisir une stratégie appropriée au travail que vous essayez d'annuler, et vous devrez peut-être déployer des efforts de conception pour rendre cette tâche parfaitement interruptible.

3
John Bollinger 27 janv. 2019 à 18:59

Vous devez définir un délai d'expiration sur le socket du serveur avant d'appeler accept() [1]:

serverSocket.setSoTimeout(100);

Ensuite, s'il n'accepte aucune connexion dans le délai imparti, accept() lancera SocketTimeoutException que vous pouvez utiliser pour décider si vous voulez continuer / arrêter d'accepter les connexions en interrompant la boucle ou en appelant {{ X2}} à nouveau

[1] https: // docs.oracle.com/javase/7/docs/api/java/net/ServerSocket.html#setSoTimeout(int)

0
Svetlin Zarev 27 janv. 2019 à 19:08

Dans ce cas, vous pouvez utiliser close méthode de ServerSocket pour interrompre la méthode d'acceptation. Cela lèvera SocketException sur le thread qui est bloqué sur l'appel d'acceptation. (Pour pouvoir l'utiliser, vous devez rendre votre objet socket serveur accessible là où vous souhaitez annuler.)

En général, la plupart des API de blocage ont un paramètre de délai d'expiration qui peut être spécifié pour l'appel de blocage. Ou ils peuvent être interrompus avec la méthode Thread.interrupt appelée pour le thread en cours d'exécution.

0
miskender 27 janv. 2019 à 18:58