web-dev-qa-db-fra.com

Est-il légal d'appeler deux fois la méthode start sur le même thread?

Le code suivant conduit à Java.lang.IllegalThreadStateException: Thread already started Lorsque j'ai appelé la méthode start()deuxième fois dans le programme.

updateUI.join();    

if (!updateUI.isAlive()) 
    updateUI.start();

Cela se produit le second temps updateUI.start() est appelé. Je l'ai parcouru plusieurs fois et le thread est appelé et s'exécute complètement avant de frapper updateUI.start().

L'appel de updateUI.run() évite l'erreur mais provoque l'exécution du thread dans le thread d'interface utilisateur (le thread d'appel, comme mentionné dans d'autres articles sur SO), ce qui n'est pas ce que je veux.

Un thread peut-il démarrer une seule fois? Si oui, que dois-je faire si je veux réexécuter le thread? Ce thread particulier fait un calcul en arrière-plan, si je ne le fais pas dans le thread, c'est fait dans le thread d'interface utilisateur et l'utilisateur a une attente déraisonnablement longue.

88
Will

De la Java API Specification pour la Thread.start méthode:

Il n'est jamais légal de démarrer un thread plus d'une fois. En particulier, un thread ne peut pas être redémarré une fois son exécution terminée.

En outre:

Jette:
IllegalThreadStateException - si le thread a déjà été démarré.

Donc oui, un Thread ne peut être démarré qu'une seule fois.

Si oui, que dois-je faire si je veux réexécuter le thread?

Si un Thread doit être exécuté plus d'une fois, alors il faut créer une nouvelle instance de Thread et appeler start dessus.

109
coobird

Exactement raison. De la documentation :

Il n'est jamais légal de démarrer un thread plus d'une fois. En particulier, un thread ne peut pas être redémarré une fois son exécution terminée.

En termes de ce que vous pouvez faire pour des calculs répétés, il semble que vous puissiez utiliser méthode invokeLater de SwingUtilities . Vous essayez déjà d'appeler directement run(), ce qui signifie que vous pensez déjà à utiliser un Runnable plutôt qu'un Thread brut. Essayez d'utiliser la méthode invokeLater uniquement sur la tâche Runnable et voyez si cela correspond un peu mieux à votre schéma mental.

Voici l'exemple de la documentation:

 Runnable doHelloWorld = new Runnable() {
     public void run() {
         // Put your UI update computations in here.
         // BTW - remember to restrict Swing calls to the AWT Event thread.
         System.out.println("Hello World on " + Thread.currentThread());
     }
 };

 SwingUtilities.invokeLater(doHelloWorld);
 System.out.println("This might well be displayed before the other message.");

Si vous remplacez cet appel println par votre calcul, il se peut que ce soit exactement ce dont vous avez besoin.

EDIT: suite au commentaire, je n'avais pas remarqué la balise Android dans le post d'origine. L'équivalent de invokeLater dans le Android travail est Handler.post(Runnable). De son javadoc:

/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is
 * attached.
 *
 * @param r The Runnable that will be executed.
 *
 * @return Returns true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */

Ainsi, dans le monde Android Android, vous pouvez utiliser le même exemple que ci-dessus, en remplaçant le Swingutilities.invokeLater Par le message approprié à un Handler.

13
Bob Cross

Non , nous ne pouvons pas relancer Thread, ce qui lève runtimeException Java.lang.IllegalThreadStateException. >

La raison est qu'une fois la méthode run () exécutée par Thread, elle passe à l'état mort.

Prenons un exemple - Penser à relancer le thread et appeler la méthode start () dessus (qui en interne va appeler la méthode run ()) est pour nous un peu comme demander à un homme mort de se réveiller et de courir. Comme, après avoir terminé sa vie, la personne passe à l'état mort.

public class MyClass implements Runnable{

    @Override
    public void run() {
           System.out.println("in run() method, method completed.");
    }

    public static void main(String[] args) {
                  MyClass obj=new MyClass();            
        Thread thread1=new Thread(obj,"Thread-1");
        thread1.start();
        thread1.start(); //will throw Java.lang.IllegalThreadStateException at runtime
    }

}

/ * OUTPUT dans la méthode run (), méthode terminée. Exception dans le thread "principal" Java.lang.IllegalThreadStateException à Java.lang.Thread.start (Source inconnue) * /

vérifiez cela

3
Sameer Kazi

La réponse qui vient d'arriver explique pourquoi vous ne devriez pas faire ce que vous faites. Voici quelques options pour résoudre votre problème réel.

Ce thread particulier fait un calcul en arrière-plan, si je ne le fais pas dans le thread, c'est fait dans le thread d'interface utilisateur et l'utilisateur a une attente déraisonnablement longue.

Videz votre propre thread et utilisez AsyncTask.

Ou créez un nouveau fil lorsque vous en avez besoin.

Ou configurez votre thread pour qu'il fonctionne hors d'une file d'attente de travail (par exemple, LinkedBlockingQueue) plutôt que de redémarrer le thread.

3
CommonsWare

Ce que vous devez faire est de créer un Runnable et de l'envelopper avec un nouveau Thread chaque fois que vous souhaitez exécuter le Runnable. Ce serait vraiment moche à faire, mais vous pouvez envelopper un thread avec un autre thread pour exécuter à nouveau le code, mais ce n'est que si vous le devez vraiment.

2
Peter Lawrey

C'est comme vous l'avez dit, un thread ne peut pas être démarré plusieurs fois.

Directement de la bouche du cheval: Java API Spec

Il n'est jamais légal de démarrer un thread plus d'une fois. En particulier, un thread ne peut pas être redémarré une fois son exécution terminée.

Si vous devez réexécuter tout ce qui se passe dans votre thread, vous devrez créer un nouveau thread et l'exécuter.

1
alanlcode

Oui, nous ne pouvons pas commencer à exécuter le thread. Il lèvera IllegalThreadStateException au moment de l'exécution - si le thread a déjà été démarré.

Et si vous avez vraiment besoin de démarrer le thread: Option 1) Si un thread doit être exécuté plus d'une fois, alors il faut créer une nouvelle instance du thread et appeler start dessus.

0
riteeka

Réutiliser un thread est une action illégale dans Java. Cependant, vous pouvez l'envelopper dans un implémentable exécutable et réexécuter cette instance à nouveau.

0
Aaron He

Un thread ne peut-il être démarré qu'une seule fois?

Oui. Vous pouvez le démarrer exactement une fois.

Si oui, que dois-je faire si je veux exécuter à nouveau le thread? Ce thread particulier fait un calcul en arrière-plan, si je ne le fais pas dans le thread que cela est fait dans le thread d'interface utilisateur et que l'utilisateur a une raison déraisonnable une longue attente.

Ne réexécutez pas le Thread. Créez plutôt Runnable et postez-le sur Handler of HandlerThread . Vous pouvez soumettre plusieurs objets Runnable. Si vous souhaitez renvoyer des données à UI Thread, avec votre méthode Runnablerun(), publiez un Message sur Handler de UI Thread et traitez handleMessage

Référez-vous à cet article pour un exemple de code:

Android: Toast dans un fil

0
Ravindra babu