44 votes

Est-ce que Thread.stop et ses amis sont toujours en sécurité en Java?

L' stop(), suspend(), et resume() en java.lang.Thread sont déconseillés parce qu'ils sont dangereux. Le Soleil de travail recommandée est d'utiliser Thread.interrupt(), mais cette approche ne fonctionne pas dans tous les cas. Par exemple, si vous appelez une méthode de bibliothèque qui n'est pas explicitement ou implicitement vérifier l' interrupted drapeau, vous n'avez pas le choix, mais à attendre l'appel à la fin.

Donc, je me demandais si il est possible de caractériser les situations où il est (sensiblement) coffre-fort pour appeler stop() sur un Fil. Par exemple, faudrait-il être sûr d' stop() un thread qui n'a rien fait mais appelez - find(...) ou match(...) sur java.util.regex.Matcher?

(S'il y a des Soleil les ingénieurs de la lecture de ce ... une réponse définitive serait vraiment apprécié.)

EDIT: Réponses que de simplement répéter le mantra que vous ne devez pas appeler stop() parce qu'il est obsolète, dangereux, quelle qu'en soient manque le point de cette question. Je sais que qu'il est réellement dangereux dans la majorité des cas, et que si il est une alternative viable, vous devez toujours utiliser à la place.

Cette question est sur le sous-ensemble des cas où il est en sécurité. Plus précisément, quel est ce sous-ensemble?

19voto

Stephen C Points 255558

Voici ma tentative de répondre à ma propre question.

Je pense que les conditions suivantes doivent être suffisants pour qu'un seul thread à être arrêté en toute sécurité à l'aide de Thread.stop():

  1. L'exécution du thread ne doit pas créer ou de muter un état (c'est à dire des objets Java, de variables de classe, des ressources externes) qui peuvent être visibles par les autres threads dans le cas où le fil est arrêté.
  2. L'exécution du thread ne doit pas utiliser notify de n'importe quel autre thread au cours de son exécution normale.
  3. Le fil ne doit pas start ou join autres threads, ou d'interagir avec les ensuite à l'aide d' stop, suspend ou resume.

(Le terme de l'exécution du thread ci-dessus couvre tous au niveau de l'application du code et de toutes les bibliothèques de code qui est exécuté par le thread.)

La première condition signifie qu'un arrêté thread va pas laisser externe des structures de données ou de ressources dans un état incohérent. Cela comprend des structures de données qu'il peut accéder (en lecture) à l'intérieur d'un mutex. La deuxième condition signifie qu'un stoppable thread ne peut pas laisser un autre thread en attente. Mais il a également interdit l'utilisation de tout mécanisme de synchronisation d'autres que simple objet mutex.

Un stoppable thread doit avoir un moyen de livrer les résultats de chaque calcul de la thread de contrôle. Ces résultats sont créé / muté par la stoppable thread, donc nous avons simplement besoin de s'assurer qu'ils ne sont pas visibles à la suite d'un thread arrêter. Par exemple, les résultats pourraient être affectés à des membres privés de l'objet Thread et "surveillé" avec un drapeau automatiquement par le thread pour dire que c'est "fait".

EDIT: Ces conditions sont très restrictives. Par exemple, pour un "évaluateur de regex" thread pour être arrêté en toute sécurité, si nous devons garantir que le moteur d'expressions régulières ne pas muter tout visible de l'extérieur de l'état. Le problème est qu'il peut faire, en fonction de comment mettre en œuvre le fil!

  1. L' Pattern.compile(...) méthodes peut mettre à jour un statique de cache de compilation les modèles, et s'ils le faisaient, ils seraient (devez) utiliser un mutex pour le faire. (En fait, l'OpenJDK version 6.0 ne met pas en cache les Modèles, mais le Soleil pourrait changer cela.)
  2. Si vous essayez d'éviter 1) par la compilation de l'expression régulière dans le contrôle de filetage et la fourniture d'une pré-instancié Matcher, alors que l'expression régulière thread ne muter visible de l'extérieur de l'état.

Dans le premier cas, nous serions probablement en difficulté. Par exemple, supposons qu'une table de hachage a été utilisé pour mettre en œuvre le cache et que le thread a été interrompu lors de la table de hachage a été réorganisé.

Dans le second cas, nous serions OK à condition que l' Matcher n'avaient pas été transmis à un autre thread, et à condition que le contrôleur de fil n'essayez pas d'utiliser l' Matcher après l'arrêt de la regex comparateur de fil.

Alors, où sommes-nous?

Eh bien, je pense avoir identifié les conditions dans lesquelles les threads sont théoriquement arrêter. Je pense aussi qu'il est théoriquement possible de manière statique d'analyser le code d'un thread (et les méthodes qu'il appelle) pour voir si ces conditions sont toujours tenir. Mais, je ne sais pas si c'est vraiment pratique.

Est-il logique? Ai-je raté quelque chose?

EDIT 2

Les choses deviennent un peu plus poilu quand vous considérez que le code que nous pourrions être en train d'essayer de tuer pourrait être non fiables:

  1. Nous ne pouvons pas compter sur les "promesses"; par exemple, les annotations sur du code non fiable qu'il est soit tuables, ou pas tuables.

  2. Nous avons réellement besoin pour être en mesure d'arrêter la non approuvé le code de faire des choses qui font qu'il peut être tué ... selon les critères établis.

Je soupçonne que cela entraînerait la modification de la JVM de comportement (par exemple, la mise en œuvre d'exécution des restrictions de ce que les threads sont autorisés pour le verrouiller ou le modifier), ou d'une mise en œuvre complète des Isolats JSR. C'est au-delà de la portée de ce que je considérais comme "fair game".

Permet donc la règle du code non fiable cas pour l'instant. Ou au moins, reconnaissez que le code malveillant peut faire des choses pour les rendre lui-même pas tuables en toute sécurité, et de mettre ce problème de côté.

10voto

djna Points 34761

Le manque de sécurité vient de l'idée de l'idée de sections critiques

Take mutex

do some work, temporarily while we work our state is inconsistent

// all consistent now

Release mutex

Si vous soufflez le fil et c'était pour être dans une section critique, puis l'objet est laissé dans un état incohérent, ce qui signifie pas utilisables en toute sécurité à partir de ce point.

Pour être sûr de tuer le thread, vous devez comprendre la totalité de la transformation de ce qui est fait dans ce thread, à savoir qu'il n'y a pas de sections critiques dans le code. Si vous utilisez le code de bibliothèque, alors vous ne pouvez pas être en mesure de voir la source et savoir que c'est sécuritaire. Même si il est sûr aujourd'hui c'est peut-être pas demain.

(Très artificiel) Exemple d'insécurité. Nous avons une liste chaînée, il n'est pas cyclique. Tous les algorithmes sont vraiment zippy parce que nous savons qu'il n'est pas cyclique. Lors de notre section critique, nous avons temporairement introduire un cycle. Nous obtenons alors soufflé avant de sortir de la section critique. Maintenant, tous les algorithmes à l'aide de la liste de boucle pour toujours. Pas de bibliothèque auteur n'aurait sûrement! Comment savez-vous? Vous ne pouvez pas supposer que le code que vous utilisez est bien écrit.

Dans l'exemple que vous montrez, c'est sûrement possible d'écrire le requreid fonctionnalité dans une interruptable façon. Plus de travail, mais possible pour être sûr.

Je vais prendre un flyer: il n'est pas documentée sous-ensemble d'Objets et de méthodes qui peuvent être utilisées dans résiliable fils, parce que pas de bibliothèque auteur veut faire de l'garanties.

1voto

Havenard Points 9023

Peut-être il ya quelque chose que je ne sais pas, mais comme java.sun.com dit, c'est dangereux parce que rien de ce fil est de la manipulation est grave risque d'être endommagé. D'autres objets, les connexions, les fichiers ouverts... pour des raisons évidentes, comme "n'éteignez pas votre Mot sans la sauvegarde de la première".

Pour cette find(...) exemple, je ne pense pas vraiment que ce serait une catastrophe pour tout simplement le coup de pied au loin avec un sutiless .stop()...

0voto

Un exemple concret serait probablement utile ici. Si quelqu'un peut suggérer une bonne alternative à l'utilisation suivante de stop, je serais très intéressé. Réécrire java.util.regex pour prendre en charge les interruptions ne compte pas.

 import java.util.regex.*;
import java.util.*;

public class RegexInterruptTest {

    private static class BadRegexException extends RuntimeException { }
        final Thread mainThread = Thread.currentThread();
        TimerTask interruptTask = new TimerTask() {
            public void run() {
                System.out.println("Stopping thread.");
                // Doesn't work:
                // mainThread.interrupt();
                // Does work but is deprecated and nasty
                mainThread.stop(new BadRegexException());
            }
        };

        Timer interruptTimer = new Timer(true);
        interruptTimer.schedule(interruptTask, 2000L);

        String s = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab";
        String exp = "(a+a+){1,100}";
        Pattern p = Pattern.compile(exp);
        Matcher m = p.matcher(s);
        try {
            System.out.println("Match: " + m.matches());
            interruptTimer.cancel();
        } catch(BadRegexException bre) {
            System.out.println("Oooops");
        } finally {
            System.out.println("All over");
        }
    }
}
 

0voto

bestsss Points 6403

Il existe des moyens pour utiliser le Thread.stop() relativement stable w/o fuite de mémoire ou des descripteurs de fichiers (FDs sont exceptionnellement fuite couchée sur *NIX), mais vous ne devez compter sur le seulement si vous êtes obligés de gérer la 3e partie du code. Ne faites jamais l'utiliser pour atteindre le résultat si vous pouvez avoir le contrôle sur le code lui-même.

Si j'utilise du Fil.arrêter le long w/ interrupt() et un peu plus de hacks des choses comme l'ajout de la journalisation des gestionnaires de re-lancer le pris au piège de ThreadDeath, ajoutant unhandleExceltionHandler, en cours d'exécution dans votre propre ThreadGroup (synchronisation sur 'em), etc...

Mais qui mérite une toute nouvelle rubrique.

Mais dans ce cas c'est la Java des Concepteurs de vous dire; et ils sont plus faisant autorité sur leur langue, puis l'un de nous :)

Juste une remarque: un certain nombre d'entre eux sont assez désemparés

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