Comment tuez-vous un java.lang.Thread
en Java?
ExecutorStatus
cette question: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Comment tuez-vous un java.lang.Thread
en Java?
ExecutorStatus
cette question: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Réponses:
Voir ce fil de Sun sur les raisons de leur dépréciationThread.stop()
. Il explique en détail pourquoi il s'agissait d'une mauvaise méthode et ce qui devrait être fait pour arrêter en toute sécurité les threads en général.
La façon dont ils recommandent est d'utiliser une variable partagée comme indicateur qui demande au thread d'arrière-plan de s'arrêter. Cette variable peut ensuite être définie par un autre objet demandant la fin du thread.
getConnection()
de java.sql.DriverManager
. Si la connexion prend trop de temps, j'essaie de tuer le thread correspondant en appelant, Thread.interrupt()
mais cela n'influence pas du tout le thread. Les Thread.stop()
travaux cependant, bien qu'oracle indique que cela ne devrait pas fonctionner sinon interrupt()
. Je me demande comment le faire fonctionner et éviter d'utiliser une méthode obsolète.
En général, vous ne le faites pas ..
Vous lui demandez d'interrompre tout ce qu'il fait en utilisant Thread.interrupt () (lien javadoc)
Une bonne explication de pourquoi est dans le javadoc ici (lien technote java)
interrupt()
méthode est appelée? La question principale est liée à la génération de journaux pour chaque nouveau thread.
En Java, les threads ne sont pas supprimés, mais l'arrêt d'un thread se fait de manière coopérative . Le thread est invité à se terminer et le thread peut ensuite s'arrêter correctement.
Souvent, un volatile boolean
champ est utilisé que le thread vérifie périodiquement et se termine lorsqu'il est défini sur la valeur correspondante.
Je n'utiliserais pas un boolean
pour vérifier si le thread doit se terminer . Si vous utilisez volatile
comme modificateur de champ, cela fonctionnera de manière fiable, mais si votre code devient plus complexe, car à la place utilise d'autres méthodes de blocage à l'intérieur de la while
boucle, il peut arriver que votre code ne se termine pas du tout ou du moins prend plus de temps à mesure que vous pourrait vouloir.
Certaines méthodes de bibliothèque de blocage prennent en charge l'interruption.
Chaque thread a déjà un statut d'interruption booléen et vous devez l'utiliser. Il peut être implémenté comme ceci:
public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
Code source adapté de Java Concurrency in Practice . Puisque la cancel()
méthode est publique, vous pouvez laisser un autre thread invoquer cette méthode comme vous le souhaitez.
Une façon consiste à définir une variable de classe et à l'utiliser comme sentinelle.
Class Outer {
public static volatile flag = true;
Outer() {
new Test().start();
}
class Test extends Thread {
public void run() {
while (Outer.flag) {
//do stuff here
}
}
}
}
Définissez une variable de classe externe, c'est-à-dire flag = true dans l'exemple ci-dessus. Réglez-le sur false pour «tuer» le thread.
volatile
pour vous assurer qu'il fonctionne correctement partout. La classe interne n'est pas statique, l'indicateur doit donc contenir une variable d'instance. L'indicateur doit être effacé dans une méthode d'accesseur afin que d'autres opérations (comme une interruption) puissent être effectuées. Le nom "flag" n'est pas descriptif.
Il existe un moyen de le faire. Mais si vous deviez l'utiliser, soit vous êtes un mauvais programmeur, soit vous utilisez un code écrit par de mauvais programmeurs. Donc, vous devriez penser à cesser d'être un mauvais programmeur ou à cesser d'utiliser ce mauvais code. Cette solution est uniquement pour les situations où il n'y a pas d'autre moyen.
Thread f = <A thread to be stopped>
Method m = Thread.class.getDeclaredMethod( "stop0" , new Class[]{Object.class} );
m.setAccessible( true );
m.invoke( f , new ThreadDeath() );
Thread.stop
même s'il est déconseillé.
Thread.stop
fait de même mais vérifie également l'accès et les autorisations. L'utilisation Thread.stop
est assez évidente, et je ne me souviens pas de la raison pour laquelle j'ai utilisé à la Thread.stop0
place de cela. Peut Thread.stop
- être n'a pas fonctionné pour mon cas particulier (Weblogic sur Java 6). Ou peut-être parce qu'il Thread.stop
est obsolète et provoque un avertissement.
Je voudrais ajouter plusieurs observations, basées sur les commentaires qui se sont accumulés.
Thread.stop()
arrêtera un thread si le gestionnaire de sécurité le permet.Thread.stop()
est dangereux. Cela dit, si vous travaillez dans un environnement JEE et que vous n'avez aucun contrôle sur le code appelé, cela peut être nécessaire; voir Pourquoi Thread.stop est déconseillé?stop()
crée une nouvelle ThreadDeathError
erreur sur le thread appelant , puis renvoie cette erreur sur le thread cible . Par conséquent, la trace de pile est généralement sans valeur.stop()
vérifie auprès du responsable de la sécurité, puis appelle stop1()
cet appel stop0()
. stop0()
est du code natif.Thread.stop()
n'a pas encore été supprimé, mais a Thread.stop(Throwable)
été supprimé dans Java 11. ( liste de diffusion , JDK-8204243 )Je voterais pour Thread.stop()
.
Comme par exemple, vous avez une opération de longue durée (comme une demande de réseau). Soi-disant, vous attendez une réponse, mais cela peut prendre du temps et l'utilisateur a navigué vers une autre interface utilisateur. Ce thread en attente est maintenant a) inutile b) un problème potentiel car lorsqu'il obtiendra un résultat, il sera complètement inutile et il déclenchera des rappels pouvant entraîner un certain nombre d'erreurs.
Tout cela et il peut faire un traitement de réponse qui pourrait être intense en CPU. Et vous, en tant que développeur, ne pouvez même pas l'arrêter, car vous ne pouvez pas lancer de if (Thread.currentThread().isInterrupted())
lignes dans tout le code.
Donc, l'incapacité d'arrêter de force un fil est bizarre.
Thread.stop()
toute façon en toute sécurité. Vous ne votez pas pour Thread.stop()
, vous demandez à chaque personne qui met en œuvre toutes les opérations qui peuvent prendre un certain temps de le rendre sans danger. Et c'est peut-être une bonne idée, mais cela n'a rien à voir avec la mise Thread.stop()
en œuvre comme moyen de demander l'avortement sans risque. Nous avons déjà interrupt
pour ça.
stop
.
La question est assez vague. Si vous vouliez dire «comment écrire un programme pour qu'un thread cesse de fonctionner quand je le veux», alors diverses autres réponses devraient être utiles. Mais si vous vouliez dire «J'ai une urgence avec un serveur, je ne peux pas redémarrer maintenant et j'ai juste besoin d'un thread particulier pour mourir, quoi qu'il arrive», alors vous avez besoin d'un outil d'intervention pour correspondre aux outils de surveillance comme jstack
.
À cet effet, j'ai créé jkillthread . Voir ses instructions d'utilisation.
Il y a bien sûr le cas où vous exécutez une sorte de code pas complètement fiable. (Personnellement, je l'ai en permettant aux scripts téléchargés de s'exécuter dans mon environnement Java. Oui, il y a des sonneries d'alarme de sécurité partout, mais cela fait partie de l'application.) Dans ce cas malheureux, vous ne faites qu'espérer en demandant aux rédacteurs de scripts pour respecter une sorte de signal booléen run / don't-run. Votre seule sécurité intégrée décente consiste à appeler la méthode d'arrêt sur le thread si, par exemple, elle s'exécute plus longtemps qu'un certain délai d'expiration.
Mais, c'est juste "décent", et non absolu, car le code pourrait intercepter l'erreur ThreadDeath (ou toute exception que vous lancez explicitement), et ne pas la renvoyer comme un thread gentleman est censé le faire. Donc, la ligne de fond est AFAIA, il n'y a pas de sécurité absolue.
Il n'y a aucun moyen de tuer gracieusement un thread.
Vous pouvez essayer d'interrompre le fil, une stratégie commune consiste à utiliser une pilule empoisonnée pour envoyer un message au fil pour qu'il s'arrête
public class CancelSupport {
public static class CommandExecutor implements Runnable {
private BlockingQueue<String> queue;
public static final String POISON_PILL = “stopnow”;
public CommandExecutor(BlockingQueue<String> queue) {
this.queue=queue;
}
@Override
public void run() {
boolean stop=false;
while(!stop) {
try {
String command=queue.take();
if(POISON_PILL.equals(command)) {
stop=true;
} else {
// do command
System.out.println(command);
}
} catch (InterruptedException e) {
stop=true;
}
}
System.out.println(“Stopping execution”);
}
}
}
BlockingQueue<String> queue=new LinkedBlockingQueue<String>();
Thread t=new Thread(new CommandExecutor(queue));
queue.put(“hello”);
queue.put(“world”);
t.start();
Thread.sleep(1000);
queue.put(“stopnow”);
En règle générale, vous ne tuez pas, n'arrêtez pas ou n'interrompez pas un thread (ou vérifiez s'il est interrompu ()), mais laissez-le se terminer naturellement.
C'est simple. Vous pouvez utiliser n'importe quelle boucle avec une variable booléenne (volatile) à l'intérieur de la méthode run () pour contrôler l'activité du thread. Vous pouvez également revenir du thread actif au thread principal pour l'arrêter.
De cette façon, vous tuez gracieusement un fil :).
Les tentatives d'arrêt brutal des threads sont de mauvaises pratiques de programmation bien connues et la preuve d'une mauvaise conception des applications. Tous les threads de l'application multithread partagent explicitement et implicitement le même état de processus et forcés de coopérer les uns avec les autres pour le garder cohérent, sinon votre application sera sujette aux bogues qui seront vraiment difficiles à diagnostiquer. Ainsi, il est de la responsabilité du développeur de fournir une assurance d'une telle cohérence via une conception d'application soignée et claire.
Il existe deux solutions principales pour les terminaisons de threads contrôlées:
Une bonne explication détaillée des problèmes liés à la terminaison abrupte des threads ainsi que des exemples de solutions erronées et correctes pour la terminaison contrôlée des threads peuvent être trouvés ici:
Voici quelques bonnes lectures sur le sujet:
Je n'ai pas réussi à faire fonctionner l'interruption sur Android, j'ai donc utilisé cette méthode, elle fonctionne parfaitement:
boolean shouldCheckUpdates = true;
private void startupCheckForUpdatesEveryFewSeconds() {
Thread t = new Thread(new CheckUpdates());
t.start();
}
private class CheckUpdates implements Runnable{
public void run() {
while (shouldCheckUpdates){
//Thread sleep 3 seconds
System.out.println("Do your thing here");
}
}
}
public void stop(){
shouldCheckUpdates = false;
}
«Tuer un fil» n'est pas la bonne expression à utiliser. Voici une façon dont nous pouvons implémenter la fin / sortie gracieuse du fil sur la volonté:
Runnable que j'ai utilisé:
class TaskThread implements Runnable {
boolean shouldStop;
public TaskThread(boolean shouldStop) {
this.shouldStop = shouldStop;
}
@Override
public void run() {
System.out.println("Thread has started");
while (!shouldStop) {
// do something
}
System.out.println("Thread has ended");
}
public void stop() {
shouldStop = true;
}
}
La classe de déclenchement:
public class ThreadStop {
public static void main(String[] args) {
System.out.println("Start");
// Start the thread
TaskThread task = new TaskThread(false);
Thread t = new Thread(task);
t.start();
// Stop the thread
task.stop();
System.out.println("End");
}
}
Thread.stop est obsolète, alors comment arrêter un thread en Java?
Toujours utiliser la méthode d'interruption et l'avenir pour demander l'annulation
Callable < String > callable = new Callable < String > () {
@Override
public String call() throws Exception {
String result = "";
try {
//assume below take method is blocked as no work is produced.
result = queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return result;
}
};
Future future = executor.submit(callable);
try {
String result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
logger.error("Thread timedout!");
return "";
} finally {
//this will call interrupt on queue which will abort the operation.
//if it completes before time out, it has no side effects
future.cancel(true);
}
public interface CustomCallable < T > extends Callable < T > {
void cancel();
RunnableFuture < T > newTask();
}
public class CustomExecutorPool extends ThreadPoolExecutor {
protected < T > RunnableFuture < T > newTaskFor(Callable < T > callable) {
if (callable instanceof CancellableTask)
return ((CancellableTask < T > ) callable).newTask();
else
return super.newTaskFor(callable);
}
}
public abstract class UnblockingIOTask < T > implements CustomCallable < T > {
public synchronized void cancel() {
try {
obj.close();
} catch (IOException e) {
logger.error("io exception", e);
}
}
public RunnableFuture < T > newTask() {
return new FutureTask < T > (this) {
public boolean cancel(boolean mayInterruptIfRunning) {
try {
this.cancel();
} finally {
return super.cancel(mayInterruptIfRunning);
}
}
};
}
}